I'm using Dagger for my dependency injection, it works well in my app but I have trouble to test it. I've followed this pattern in order to create the modules depenency graph : https://github.com/pyricau/shipfaster/blob/master/src/main/java/com/squareup/shipfaster/common/ShipFasterApplication.java
Now, in my MainActivity test class, I want to be able to verify interaction with a mock when the Activity onResume() method is called.
Here is the class :
@Config(emulateSdk = 18)
@RunWith(RobolectricDaggerTestRunner.class)
public class MainActivityTest extends TestCase {
@Inject MainActivity sut;
public @Mock MyObject mockMyObject;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ObjectGraph.create(new TestModule()).inject(this);
}
@Test
public void testThatMyActivityDelegatesDoSomethingToMyObject(){
//init
ActivityController<MainActivity> activityController = ActivityController.of(sut);
//run
activityController.create().start().resume();
//verify
Mockito.verify(mockMyObject).doSomething();
}
@Module(
includes = {ActivityModule.class},
injects = MainActivityTest.class,
overrides = true,
library = true
)
class TestModule {
@Provides
MyObject provideMyObject() {
return mockMyObject;
}
}
}
From what I can see, the onCreate()
method is called but a real instance of myObject
is used, not the mocked one. The test failed with a "wanted but not invoked - Actually, there were zero interactions with this mock." error.
Maybe this is because the MainActivity I'm trying to create using Robolectric is not associated with my TestModule because it's created in the Application level, but I manage to make that test to pass by explicitly call a method on the MainActivity and put the myObject.doSomething() in there, but what I need is to test Android lifecycle calls.
Any idea on how can I manage to test this?
The real object is used because I guess you have initialization of ObjectGraph
in your Application
class. When you call ((Application) getApplication()).inject(this)
during tests you are using the same ObjectGraph
as when you just run your application.
In this test you are creating completly new ObjectGraph
with mock instance of MyObject
. This mock is injected only in MainActivityTest
because when in MainActivity
inject()
is called it uses ObjectGraph
made in Application
.
What you can do is to make TestApplication
class (it has to have the same package as your Application
class but needs to be in test directory) whitch extends your application and there add your TestModule
to override real instances with mocks. For example in this way:
package com.example.myapp;
public class MyApplication extends Application {
ObjectGraph graph;
private Account currentAccount;
@Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
init();
}
void init() {
// initialization stuff should not be called in tests
}
List<Object> getModules() {
List<Object> modules = new ArrayList<>();
modules.add(new ActivityModule(this));
return modules;
}
public void inject(Object object) {
graph.inject(object);
}
}
package com.example.myapp;
public class TestMyApplication extends MyApplication {
@Override
void init() {
}
@Override
List<Object> getModules() {
modules = super.getModules();
modules.add(new TestModule());
return modules;
}
}
I had the same problems some time ago but I managed to solve it like this: Android Testing with Robolectric and Dagger
WojciechKo suggestion may work in some cases but my solution can work without overriding the Application class in your tests.The difference is that you still need to provide a way to inject Dagger modules in your application rather than instantiating them in the Application class. This way, in your test class you can add the TestModule to override the one that is used in the real Application class.
If you have problems with the solution presented in that link let me know and we can further investigate the problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.