12

我正在尝试使用Mockito测试活动& Dagger。我已经能够在我的应用程序中向Activity中注入依赖项,但在测试Activity时,我无法将注入模拟注入到Activity中。我应该注入Activity来测试还是让getActivity()创建它?使用Dagger进行Android功能测试

public class MainActivityTest extends 
    ActivityInstrumentationTestCase2<MainActivity> { 

@Inject Engine engineMock; 
private MainActivity mActivity; 
private Button mLogoutBtn; 


public MainActivityTest() { 
    super(MainActivity.class); 
} 

@Override 
protected void setUp() throws Exception { 
    super.setUp(); 

    // Inject engineMock to test 
    ObjectGraph.create(new TestModule()).inject(this); 
} 

@Override 
protected void tearDown() { 
    if (mActivity != null) 
     mActivity.finish(); 
} 

@Module(
includes = MainModule.class, 
entryPoints = MainActivityTest.class, 
overrides = true 
) 

static class TestModule { 
    @Provides 
    @Singleton 
    Engine provideEngine() { 
     return mock(Engine.class); 
    } 
} 

@UiThreadTest 
public void testLogoutButton() { 

    when(engineMock.isLoggedIn()).thenReturn(true); 

    mActivity = getActivity(); 
    mLogoutBtn = (Button) mActivity.findViewById(R.id.logoutButton); 

    // how to inject engineMock to Activity under test? 
    ObjectGraph.create(new TestModule()).inject(this.mActivity); 

    assertTrue(mLogoutBtn.isEnabled() == true); 
} 
} 

回答

1

我做了一些更多的实验,发现Dagger在注入测试时无法正确创建活动。在新版本的测试中,testDoSomethingCalledOnEngine通过,但OnCreate未在MainActivity上调用。第二个测试testDoSomethingUI失败,实际上有两个MainActivity实例,onCreate被调用到另一个实例(由ActivityInstrumentationTestCase2创建),但不是另一个。也许Square的开发人员只考虑用Robolectric而不是Android仪器测试来测试Activites?

public class MainActivityTest extends 
    ActivityInstrumentationTestCase2<MainActivity> { 

@Inject Engine engineMock; 
@Inject MainActivity mActivity; 

public MainActivityTest() { 
    super(MainActivity.class); 
} 

@Override 
protected void setUp() throws Exception { 
    super.setUp(); 

    // Inject engineMock to test & Activity under test 
    ObjectGraph.create(new TestModule()).inject(this); 
} 


@Module(
includes = MainModule.class, 
entryPoints = MainActivityTest.class, 
overrides = true 
) 

static class TestModule { 
    @Provides 
    @Singleton 
    Engine provideEngine() { 
     return mock(Engine.class); 
    } 
} 

public void testDoSomethingCalledOnEngine() { 
    when(engineMock.isLoggedIn()).thenReturn(true); 
    mActivity.onSomethingHappened(); 
    verify(engineMock).doSomething(); 
} 

@UiThreadTest 
public void testDoSomethingUI() { 
    when(engineMock.isLoggedIn()).thenReturn(true); 
    mActivity.onSomethingHappened(); 
    Button btn = (Button) mActivity.findViewById(R.id.logoutButton); 
    String btnText = btn.getText().toString(); 
    assertTrue(btnText.equals("Log out")); 
} 

}

+3

我们的活动注入自己的onCreate(基类)。我们使用应用程序类的开发版本添加仅限dev模块到对象图中。 – 2013-05-10 01:30:17

+5

@JakeWharton你可以指出一个例子,你有Dagger注入模拟UI测试吗?我从你创建的一些插件知道,你已经和Espresso一起工作过。一个例子,你如何实现测试嘲笑的咖啡测试,将是非常宝贵的! – 2014-04-23 02:10:06

6

我用和的Mockito匕首功能测试。 关键概念是您的测试类继承自ActivityUnitTestCase,而不是ActivityInstrumentationTestCase2;后者超类调用Activity的生命周期方法onStart()来阻止你注入你的测试双击依赖项,但是用第一个超类可以处理生命周期更加细化。

您可以看到使用匕首1.0.0和对的Mockito测试活动我的工作实例和片段中:

https://github.com/IIIRepublica/android-civicrm-test

下测试该项目是:

https://github.com/IIIRepublica/android-civicrm

希望这可以帮助你