I am using Dagger as dependency injection framwork. It's working well so far but I am having an issue while using Dagger for Android unit testing and can't figure out why (Probably because of an incorrect use of Dagger).
I am having the following exception
java.lang.IllegalArgumentException: Failed to construct com.couchsurfing.mobile.android.CSApplication$ProdModule
at dagger.internal.plugins.reflect.ReflectiveModuleAdapter.newModule(ReflectiveModuleAdapter.java:94)
at dagger.internal.RuntimeAggregatingPlugin.getModuleAdapter(RuntimeAggregatingPlugin.java:99)
at dagger.internal.RuntimeAggregatingPlugin.collectIncludedModulesRecursively(RuntimeAggregatingPlugin.java:85)
at dagger.internal.RuntimeAggregatingPlugin.getAllModuleAdapters(RuntimeAggregatingPlugin.java:71)
at dagger.ObjectGraph.makeGraph(ObjectGraph.java:115)
at dagger.ObjectGraph.create(ObjectGraph.java:103)
at com.couchsurfing.mobile.android.core.MessageManagerTest.setUp(MessageManagerTest.java:34)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1661)
Caused by: java.lang.NoSuchMethodException: <init> []
at java.lang.Class.getConstructorOrMethod(Class.java:460)
at java.lang.Class.getDeclaredConstructor(Class.java:588)
at dagger.internal.plugins.reflect.ReflectiveModuleAdapter.newModule(ReflectiveModuleAdapter.java:88)
... 15 more
The code generating the exception is the following:
public class MessageManagerTest extends InstrumentationTestCase {
@Inject
MessageManager mMessageManager;
@Inject
MessageOperations.Factory mMOFactory;
@Inject
Context mAppContext;
@Override
public void setUp() {
ObjectGraph.create(new TestModule()).inject(this);
}
@Module(
includes = CSApplication.ProdModule.class,
entryPoints = MessageManagerTest.class,
overrides = true)
static class TestModule {
@Provides
MessageOperations.Factory provideMessageOperationsFactory() {
return Mockito.mock(MessageOperations.Factory.class);
}
@Provides
Context provideAppContext() {
return Mockito.mock(Context.class);
}
}
public void testCreateMessage() throws RemoteException, OperationApplicationException {
...
}
}
Note that the module CSApplication$ProdModule is used in the production version of the app and works well.
You need to give ProdModule a no-args non-private constructor. And the class needs to be static. Without this Dagger can't construct your module.
You need to either add a no-args accessible (in this case, public) constructor or you need to pass in an instance of the module. If you don't pass in an instance, then Dagger has to construct the module itself, which it cannot do if there is no accessible no-args constructor.