使用Dagger进行Android功能测试

12

我正在尝试使用Mockito和Dagger测试一个Activity。 我已经能够在我的应用程序中将依赖项注入到Activity中,但是当测试该Activity时,我无法将Mock注入到Activity中。 我应该将Activity注入进行测试,还是让getActivity()创建它?


我试图使用Mockito和Dagger来测试一个Activity。我已经成功地将依赖项注入到应用程序的Activity中,但是在测试Activity时,我无法注入mock对象。我不确定是将Activity注入到测试中,还是让getActivity()方法创建它。请问应该如何处理?
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);
}
}
3个回答

6
我使用Mockito和Dagger进行功能测试。 关键概念是,您的测试类继承ActivityUnitTestCase,而不是ActivityInstrumentationTestCase2;后者超类调用Activity的onStart()生命周期方法,阻止您注入测试双重依赖项,但是通过第一个超类,您可以更细粒度地处理生命周期。 您可以查看我的工作示例,使用dagger-1.0.0和mockito测试活动和片段:

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

被测试的项目在以下位置:

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

希望这可以帮到您。

1

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

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(在一个基类中)中插入自身。我们使用应用程序类的开发版本向对象图中添加仅限开发的模块。 - Jake Wharton
5
@JakeWharton,你能否举个例子,说明在UI测试中,你是如何使用Dagger注入模拟对象的?我知道你曾经使用过Espresso,因此了解您如何为Espresso测试实现模拟对象的示例将非常有价值!请提供一份示例。 - KG -

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接