Android functional testing with Dagger

2019-03-25 00:35发布

I’m trying to test an Activity with Mockito & Dagger. I have been able to inject dependencies to Activity in my application but when testing the Activity, I have not been able to inject mock to the Activity. Should I inject Activity to test or let getActivity() create it?

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条回答
倾城 Initia
2楼-- · 2019-03-25 01:04

I use Mockito and Dagger for functional testing. The key concept is that your test class inherits from ActivityUnitTestCase, instead of ActivityInstrumentationTestCase2; the latter super-class call onStart() life-cycle method of Activity blocking you for inject your test doubles dependencies, but with first super-class you can handle the life-cycle more fine-grained.

You can see my working examples using dagger-1.0.0 and mockito for test Activities and Fragments in:

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

The project under test is in:

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

Hope this helps you

查看更多
不美不萌又怎样
3楼-- · 2019-03-25 01:15

I have put everything together and made demo app that shows how to test with dagger: https://github.com/vovkab/dagger-unit-test

Here is my pervious answer with more details:
https://stackoverflow.com/a/24393265/369348

查看更多
相关推荐>>
4楼-- · 2019-03-25 01:23

I did some more experimenting and found out that Dagger is not able to create activity correctly when it is injected to test. In the new version of test, testDoSomethingCalledOnEngine passes but onCreate is not called on the MainActivity. The second test, testDoSomethingUI fails and there are actually two instances of MainActivity, onCreate gets called to the other instance (created by ActivityInstrumentationTestCase2 I quess) but not to the other. Maybe the developers at Square only thought about testing Activites with Robolectric instead of Android instrumentation test?

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"));  
}

}

查看更多
登录 后发表回答