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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With