Skip to content

Commit b102b6d

Browse files
author
Ivan Carballo
committed
Add an test strategy parameter in the ApplicationTestModule that allows injecting either a mock, spy or real DataManager during tests
1 parent dc22e6c commit b102b6d

File tree

10 files changed

+66
-37
lines changed

10 files changed

+66
-37
lines changed

app/src/androidTest/java/uk/co/ribot/androidboilerplate/MainActivityTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import rx.Observable;
1717
import uk.co.ribot.androidboilerplate.data.model.Ribot;
1818
import uk.co.ribot.androidboilerplate.test.common.TestDataFactory;
19+
import uk.co.ribot.androidboilerplate.test.common.injection.module.ApplicationTestModule;
1920
import uk.co.ribot.androidboilerplate.test.common.rules.ClearDataRule;
2021
import uk.co.ribot.androidboilerplate.test.common.rules.TestComponentRule;
2122
import uk.co.ribot.androidboilerplate.ui.main.MainActivity;
@@ -30,16 +31,17 @@
3031
@RunWith(AndroidJUnit4.class)
3132
public class MainActivityTest {
3233

33-
public final TestComponentRule component =
34-
new TestComponentRule(InstrumentationRegistry.getTargetContext(), true);
34+
public final TestComponentRule component = new TestComponentRule(
35+
InstrumentationRegistry.getTargetContext(),
36+
ApplicationTestModule.DataManagerTestStrategy.SPY);
3537
public final ClearDataRule clearDataRule = new ClearDataRule(component);
3638
public final ActivityTestRule<MainActivity> main =
3739
new ActivityTestRule<>(MainActivity.class, false, false);
3840

3941
// TestComponentRule needs to go first to make sure the Dagger ApplicationTestComponent is set
4042
// in the Application before any Activity is launched.
4143
@Rule
42-
public TestRule chain = RuleChain.outerRule(component).around(clearDataRule).around(main);
44+
public final TestRule chain = RuleChain.outerRule(component).around(clearDataRule).around(main);
4345

4446
@Test
4547
public void listOfRibotsShows() {

app/src/commonTest/java/uk/co/ribot/androidboilerplate/test/common/TestDataManager.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package uk.co.ribot.androidboilerplate.test.common;
22

33
import android.app.Application;
4-
import android.content.Context;
54

65
import org.mockito.Mockito;
76

app/src/commonTest/java/uk/co/ribot/androidboilerplate/test/common/injection/module/ApplicationTestModule.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,24 @@
2020
*/
2121
@Module
2222
public class ApplicationTestModule {
23+
24+
public enum DataManagerTestStrategy { REAL, MOCK, SPY }
25+
2326
private final Application mApplication;
24-
private boolean mMockableDataManager;
27+
private DataManagerTestStrategy mDataManagerTestStrategy;
2528

26-
public ApplicationTestModule(Application application, boolean mockableDataManager) {
29+
/**
30+
* Create a module that provides application dependencies for a testing environment.
31+
* It takes a dataManagerTestStrategy that can be 1) REAL: provides real instances of
32+
* the DataManager, 2) MOCK: provides Mockito mock instances of the DataManager that must be
33+
* stubbed, 3) SPY: provides an Mockito spy instance of the DataManager that can be partially
34+
* stubbed, you can read more about Mockito spies and mocks to help you choose the best
35+
* strategy for your tests.
36+
*/
37+
public ApplicationTestModule(Application application,
38+
DataManagerTestStrategy dataManagerTestStrategy) {
2739
mApplication = application;
28-
mMockableDataManager = mockableDataManager;
40+
mDataManagerTestStrategy = dataManagerTestStrategy;
2941
}
3042

3143
@Provides
@@ -37,8 +49,14 @@ Application provideApplication() {
3749
@Provides
3850
@Singleton
3951
DataManager provideDataManager() {
40-
TestDataManager testDataManager = new TestDataManager(mApplication);
41-
return mMockableDataManager ? spy(testDataManager) : testDataManager;
52+
switch (mDataManagerTestStrategy) {
53+
case MOCK:
54+
return mock(TestDataManager.class);
55+
case SPY:
56+
return spy(new TestDataManager(mApplication));
57+
default:
58+
return new TestDataManager(mApplication);
59+
}
4260
}
4361

4462
@Provides

app/src/commonTest/java/uk/co/ribot/androidboilerplate/test/common/injection/module/DataManagerTestModule.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package uk.co.ribot.androidboilerplate.test.common.injection.module;
22

33
import android.app.Application;
4-
import android.content.Context;
5-
6-
import org.mockito.Mockito;
74

85
import dagger.Module;
96
import dagger.Provides;

app/src/commonTest/java/uk/co/ribot/androidboilerplate/test/common/rules/TestComponentRule.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,35 @@ public class TestComponentRule implements TestRule {
2626

2727
private TestComponent mTestComponent;
2828
private Context mContext;
29-
private boolean mMockableDataManager;
29+
private ApplicationTestModule.DataManagerTestStrategy mDataManagerTestStrategy;
3030

3131
/**
32-
* If mockableDataManager is true, it will crate a data manager using Mockito.spy()
33-
* Spy objects call real methods unless they are stubbed. So the DataManager will work as
34-
* usual unless an specific method is mocked.
35-
* A full mock DataManager is not an option because there are several methods that still
36-
* need to return the real value, i.e dataManager.getSubscribeScheduler()
32+
* Create a rule that sets up a Dagger TestComponent to inject test dependencies such as mocks.
33+
*
34+
* It takes a dataManagerTestStrategy that can be:
35+
* 1) REAL: injects real instances of the DataManager
36+
* 2) MOCK: injects Mockito mock instances of the DataManager that must be stubbed
37+
* 3) SPY: injects an Mockito spy instance of the DataManager that can be partially stubbed.
38+
* You can read more about Mockito spies and mocks to help you choose the best
39+
* strategy for your tests.
3740
*/
38-
public TestComponentRule(Context context, boolean mockableDataManager) {
39-
init(context, mockableDataManager);
41+
public TestComponentRule(Context context,
42+
ApplicationTestModule.DataManagerTestStrategy dmTestStrategy) {
43+
init(context, dmTestStrategy);
4044
}
4145

46+
/**
47+
* Create a rule that sets up a Dagger TestComponent to inject test dependencies such as mocks.
48+
* It will use the default dataManagerTestStrategy that is REAL.
49+
*/
4250
public TestComponentRule(Context context) {
43-
init(context, false);
51+
init(context, ApplicationTestModule.DataManagerTestStrategy.REAL);
4452
}
4553

46-
private void init(Context context, boolean mockableDataManager) {
54+
private void init(Context context,
55+
ApplicationTestModule.DataManagerTestStrategy dataManagerTestStrategy) {
4756
mContext = context;
48-
mMockableDataManager = mockableDataManager;
57+
mDataManagerTestStrategy = dataManagerTestStrategy;
4958
}
5059

5160
public TestComponent getTestComponent() {
@@ -56,6 +65,15 @@ public Context getContext() {
5665
return mContext;
5766
}
5867

68+
public ApplicationTestModule.DataManagerTestStrategy getDataManagerTestStrategy() {
69+
return mDataManagerTestStrategy;
70+
}
71+
72+
/**
73+
* This could return a real instance, a Mockito.mock or a Mockito.spy depending on the
74+
* strategy chosen. You can use {@link #getDataManagerTestStrategy()} to get the current
75+
* strategy.
76+
*/
5977
public TestDataManager getDataManager() {
6078
return (TestDataManager) mTestComponent.dataManager();
6179
}
@@ -75,7 +93,7 @@ public PreferencesHelper getPreferencesHelper() {
7593
private void setupDaggerTestComponentInApplication() {
7694
BoilerplateApplication application = BoilerplateApplication.get(mContext);
7795
ApplicationTestModule module = new ApplicationTestModule(application,
78-
mMockableDataManager);
96+
mDataManagerTestStrategy);
7997
mTestComponent = DaggerTestComponent.builder()
8098
.applicationTestModule(module)
8199
.build();

app/src/main/java/uk/co/ribot/androidboilerplate/data/DataManager.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package uk.co.ribot.androidboilerplate.data;
22

33
import android.app.Application;
4-
import android.content.Context;
5-
import android.test.mock.MockApplication;
64

75
import com.squareup.otto.Bus;
86

app/src/main/java/uk/co/ribot/androidboilerplate/injection/module/DataManagerModule.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package uk.co.ribot.androidboilerplate.injection.module;
22

33
import android.app.Application;
4-
import android.content.Context;
54

65
import dagger.Module;
76
import dagger.Provides;

app/src/main/java/uk/co/ribot/androidboilerplate/injection/module/PresentersModule.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package uk.co.ribot.androidboilerplate.injection.module;
22

33
import android.app.Application;
4-
import android.content.Context;
5-
6-
import java.lang.ref.WeakReference;
74

85
import dagger.Module;
96
import dagger.Provides;

app/src/test/java/uk/co/ribot/androidboilerplate/MainPresenterTest.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@
1010

1111
import rx.Observable;
1212
import uk.co.ribot.androidboilerplate.data.model.Ribot;
13-
import uk.co.ribot.androidboilerplate.util.MockDependenciesHelper;
1413
import uk.co.ribot.androidboilerplate.test.common.TestDataFactory;
14+
import uk.co.ribot.androidboilerplate.test.common.runner.RxJavaTestRunner;
1515
import uk.co.ribot.androidboilerplate.ui.main.MainMvpView;
1616
import uk.co.ribot.androidboilerplate.ui.main.MainPresenter;
17-
import uk.co.ribot.androidboilerplate.test.common.runner.RxJavaTestRunner;
17+
import uk.co.ribot.androidboilerplate.util.MockDependenciesHelper;
1818

1919
import static org.mockito.Matchers.anyListOf;
20-
import static org.mockito.Matchers.anyString;
2120
import static org.mockito.Mockito.doReturn;
2221
import static org.mockito.Mockito.mock;
2322
import static org.mockito.Mockito.never;
@@ -51,7 +50,7 @@ public void loadRibotsReturnsRibots() {
5150
mMainPresenter.loadRibots();
5251
verify(mMockMainMvpView).showRibots(ribots);
5352
verify(mMockMainMvpView, never()).showRibotsEmpty();
54-
verify(mMockMainMvpView, never()).showError(anyString());
53+
verify(mMockMainMvpView, never()).showError();
5554
}
5655

5756
@Test
@@ -63,7 +62,7 @@ public void loadRibotsReturnsEmptyList() {
6362
mMainPresenter.loadRibots();
6463
verify(mMockMainMvpView).showRibotsEmpty();
6564
verify(mMockMainMvpView, never()).showRibots(anyListOf(Ribot.class));
66-
verify(mMockMainMvpView, never()).showError(anyString());
65+
verify(mMockMainMvpView, never()).showError();
6766
}
6867

6968
@Test
@@ -73,7 +72,7 @@ public void loadRibotsFails() {
7372
.getRibots();
7473

7574
mMainPresenter.loadRibots();
76-
verify(mMockMainMvpView).showError(anyString());
75+
verify(mMockMainMvpView).showError();
7776
verify(mMockMainMvpView, never()).showRibotsEmpty();
7877
verify(mMockMainMvpView, never()).showRibots(anyListOf(Ribot.class));
7978
}

app/src/test/java/uk/co/ribot/androidboilerplate/util/MockDependenciesHelper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ public class MockDependenciesHelper {
2929

3030
public MockDependenciesHelper() {
3131
mMockApplication = Mockito.mock(BoilerplateApplication.class);
32+
ApplicationTestModule applicationTestModule = new ApplicationTestModule(mMockApplication,
33+
ApplicationTestModule.DataManagerTestStrategy.MOCK);
3234
mTestComponent = DaggerTestComponent.builder()
33-
.applicationTestModule(new ApplicationTestModule(mMockApplication, true))
35+
.applicationTestModule(applicationTestModule)
3436
.build();
3537

3638
when(mMockApplication.getComponent())

0 commit comments

Comments
 (0)