Mock dependent component's dependency with DaggerMock - android

I want to write Espresso tests for an app so I'm trying DaggerMock to
mock some external dependencies like local storage.
My Dagger setup consists of an ApplicationComponent with 3 modules (DatabaseModule, DataModule and ApplicationModule) and for the screen( a Fragment ) I want to test I have also another component which depends on ApplicationComponent.
What I have tried so far is :
#Rule public DaggerMockRule<ApplicationComponent> daggerRule =
new DaggerMockRule<>(ApplicationComponent.class, new DatabaseModule(), new DataModule(application),
new ApplicationModule(application)).set(
component -> {
MyApplication app =
(MyApplication) InstrumentationRegistry.getInstrumentation()
.getTargetContext()
.getApplicationContext();
app.setComponent(component);
});
#Rule
public final DaggerMockRule<FeedComponent> rule = new DaggerMockRule<>(
FeedComponent.class, new FeedDataSourceModule(),
new FeedDownloadImageUseCaseModule(), new FeedServiceModule(), new FeedPresenterModule(null))
.addComponentDependency(ApplicationComponent.class, new DatabaseModule(), new DataModule(application), new ApplicationModule(application))
.set(component -> localDataSource = component.localDataSource());
#Mock FeedDao feedDao;
#Mock NetworkUtils networkUtils;
#Mock FeedLocalDataSource localDataSource;
where localDataSource is actually the dependency I want to mock and it's build in FeedDataSourceModule :
#Module
public class FeedDataSourceModule {
#Provides
#FragmentScope
public FeedItemMapper providesFeedItemMapper() {
return new FeedItemMapper();
}
#Provides
#FragmentScope
public FeedLocalDataSource providesFeedLocalDataSource(FeedDao feedDao, FeedRequestDetailsDao detailsDao, FeedItemMapper mapper) {
return new FeedLocalDataSourceImpl(feedDao, detailsDao, mapper);
}
#Provides
#FragmentScope
public FeedRemoteDataSource providesFeedRemoteDataSource(FeedService feedService, FlagStateService flagStateService,
#Named("Api-Token") String apiToken, #Named("Screen-Size") String screenSize,
#Named("Account-Id") String accountId) {
return new FeedRemoteDataSourceImpl(feedService, flagStateService, apiToken, screenSize, accountId);
}
}
and also the FeedComponent with the dependency on ApplicationComponent :
#FragmentScope
#Component( dependencies = ApplicationComponent.class,
modules = {
FeedPresenterModule.class,
FeedServiceModule.class,
FeedDataSourceModule.class,
FeedDownloadImageUseCaseModule.class})
public interface FeedComponent {
#Named("Api-Token") String getApiToken();
#Named("Api-Key") String getApiKey();
FeedLocalDataSource localDataSource();
FeedRemoteDataSource remoteDataSource();
void inject(FeedFragment feedFragment);
}
With the two #Rules I posted above I can confirm that NetworkUtils indeed seems to have been mocked correctly since I have used Mockito.when() to return false value and by using a breakpoint in my code I can see the value is always false :
when(networkUtils.isOnline())
.thenReturn(false);
But this is not true for localDataSource which gives me null when I'm calling localDataSource.getFeedSorted() although I have declared :
when(localDataSource.getFeedSorted())
.thenReturn(Flowable.just(feedList));
Just in case it helps, this is how I inject the dependencies from FeedComponent :
DaggerFeedComponent.builder()
.applicationComponent(MyApplication.getApplicationComponent())
.feedPresenterModule(new FeedPresenterModule(this))
.build()
.inject(this);

Why are you using two DaggerMock rules in a test? I think you can use a single rule like in this example.

Related

How to mock sharedpreferences for android instrumentation tests?

I have a preference util class to store and retrieve the data in shared preferences in a single place.
Prefutils.java:
public class PrefUtils {
private static final String PREF_ORGANIZATION = "organization";
private static SharedPreferences getPrefs(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
private static SharedPreferences.Editor getEditor(Context context) {
return getPrefs(context).edit();
}
public static void storeOrganization(#NonNull Context context,
#NonNull Organization organization) {
String json = new Gson().toJson(organization);
getEditor(context).putString(PREF_ORGANIZATION, json).apply();
}
#Nullable public static Organization getOrganization(#NonNull Context context) {
String json = getPrefs(context).getString(PREF_ORGANIZATION, null);
return new Gson().fromJson(json, Organization.class);
}
}
Sample code showing PrefUtils usage in LoginActivity.java:
#Override public void showLoginView() {
Organization organization = PrefUtils.getOrganization(mActivity);
mOrganizationNameTextView.setText(organization.getName());
}
List of androidTestCompile dependencies in build.gradle:
// Espresso UI Testing dependencies.
androidTestCompile "com.android.support.test.espresso:espresso-core:$project.ext.espressoVersion"
androidTestCompile "com.android.support.test.espresso:espresso-contrib:$project.ext.espressoVersion"
androidTestCompile "com.android.support.test.espresso:espresso-intents:$project.ext.espressoVersion"
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2:'
src/androidTest/../LoginScreenTest.java
#RunWith(AndroidJUnit4.class) #LargeTest public class LoginScreenTest {
#Rule public ActivityTestRule<LoginActivity> mActivityTestRule =
new ActivityTestRule<>(LoginActivity.class);
#Before public void setUp() throws Exception {
when(PrefUtils.getOrganization(any()))
.thenReturn(HelperUtils.getFakeOrganization());
}
}
The above code to return fakeOrganization was not working, running the tests on login activity results in NullPointerException in line mOrganizationNameTextView.setText(organization.getName()); defined in the above LoginActivity.java class.
How to solve the above issue?
Approach-1:
Expose SharedPreference with application scope using Dagger2 and use it like #Inject SharedPreferences mPreferences in activity/fragment.
Sample code using the above approach to save(write) a custom preference:
SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(PREF_ORGANIZATION, mGson.toJson(organization));
editor.apply();
To read a custom preference:
String organizationString = mPreferences.getString(PREF_ORGANIZATION, null);
if (organizationString != null) {
return mGson.fromJson(organizationString, Organization.class);
}
If you use it like above it results in breaking the DRY principle, since the code will be repeated in multiple places.
Approach-2:
This approach is based on the idea of having a separate preference class like StringPreference/ BooleanPreference which provides wrapper around the SharedPreferences code to save and retrieve values.
Read the below posts for detailed idea before proceeding with the solution:
Persist your data elegantly: U2020 way by #tasomaniac
Espresso 2.1: ActivityTestRule by chiuki
Dagger 2 + Espresso 2 + Mockito
Code:
ApplicationModule.java
#Module public class ApplicationModule {
private final MyApplication mApplication;
public ApplicationModule(MyApplication application) {
mApplication = application;
}
#Provides #Singleton public Application provideApplication() {
return mApplication;
}
}
DataModule.java
#Module(includes = ApplicationModule.class) public class DataModule {
#Provides #Singleton public SharedPreferences provideSharedPreferences(Application app) {
return PreferenceManager.getDefaultSharedPreferences(app);
}
}
GsonModule.java
#Module public class GsonModule {
#Provides #Singleton public Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
}
ApplicationComponent.java
#Singleton #Component(
modules = {
ApplicationModule.class, DataModule.class, GsonModule.class
}) public interface ApplicationComponent {
Application getMyApplication();
SharedPreferences getSharedPreferences();
Gson getGson();
}
MyApplication.java
public class MyApplication extends Application {
#Override public void onCreate() {
initializeInjector();
}
protected void initializeInjector() {
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
}
OrganizationPreference.java
public class OrganizationPreference {
public static final String PREF_ORGANIZATION = "pref_organization";
SharedPreferences mPreferences;
Gson mGson;
#Inject public OrganizationPreference(SharedPreferences preferences, Gson gson) {
mPreferences = preferences;
mGson = gson;
}
#Nullable public Organization getOrganization() {
String organizationString = mPreferences.getString(PREF_ORGANIZATION, null);
if (organizationString != null) {
return mGson.fromJson(organizationString, Organization.class);
}
return null;
}
public void saveOrganization(Organization organization) {
SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(PREF_ORGANIZATION, mGson.toJson(organization));
editor.apply();
}
}
Wherever you need the preference just inject it using Dagger #Inject OrganizationPreference mOrganizationPreference;.
For androidTest, I'm overriding the preference with a mock preference. Below is my configuration for android tests:
TestDataModule.java
public class TestDataModule extends DataModule {
#Override public SharedPreferences provideSharedPreferences(Application app) {
return Mockito.mock(SharedPreferences.class);
}
}
MockApplication.java
public class MockApplication extends MyApplication {
#Override protected void initializeInjector() {
mApplicationComponent = DaggerTestApplicationComponent.builder()
.applicationModule(new TestApplicationModule(this))
.dataModule(new TestDataModule())
.build();
}
}
LoginScreenTest.java
#RunWith(AndroidJUnit4.class) public class LoginScreenTest {
#Rule public ActivityTestRule<LoginActivity> mActivityTestRule =
new ActivityTestRule<>(LoginActivity.class, true, false);
#Inject SharedPreferences mSharedPreferences;
#Inject Gson mGson;
#Before public void setUp() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
MyApplication app = (MyApplication) instrumentation.getTargetContext().getApplicationContext();
TestApplicationComponent component = (TestApplicationComponent) app.getAppComponent();
component.inject(this);
when(mSharedPreferences.getString(eq(OrganizationPreference.PREF_ORGANIZATION),
anyString())).thenReturn(mGson.toJson(HelperUtils.getFakeOrganization()));
mActivityTestRule.launchActivity(new Intent());
}
}
Make sure you have dexmaker mockito added in build.gradle
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2:'
Unfortunately Mockito cannot perform what you are looking for on its own. You have two options, one is to use Power Mock and the other is to change Prefutils into a normal class and instead use a Dependency Injection Framework.
Power Mock
Nice and simple, this will let you mock static methods, check out this SO post for details. On the downside it may result in other issues based on the comments in that SO post.
Dependency Injection Approach (my original answer)
You are trying to write a UI test with some of the behavior of the application "mocked". Mockito is built to let you write Unit tests where you test a specific object (or group of objects) and mock some of their behavior.
You can see some examples of how mockito is used in these tests (1, 2). None of them test the UI, instead they instantiate an object "stub"/"mock" some if its behavior and then test the rest.
To achieve what you want you will instead need a dependency injection framework. This allows you to change the "implementation" of some of your application based on whether you are running the actual application or a test.
The details of how you mock behavior of your classes/objects varies from framework to framework. This blog post goes over how to use Dagger 2 with Mockito and espresso you can apply the same approach for your tests. It also has links to presentations that give more background on dagger 2.
If you don't like dagger 2 then you can also checkout RoboGuice and Dagger. Just note, I do not think butter-knife will fit your needs as it doesn't support injection of Pojos.

Android Tests: use Dagger2 + Gradle

I understand how Dagger2 works,
I understand it allows to easily swap dependencies, so we can use mocks for testing.
Point is that I am not sure I understand how am I supposed to provide different Dagger2 Components implementations for testing and for debug/production.
Would I need to create 2 Gradle productFlavors (e.g "Production"/"Test")
that would contain 2 different Components definition?
Or can I specify that I want to use the mock Component for test compile and the non mock Component for non test builds?
I am confused, please some clarification would be great!
Thanks a lot!
Unit testing
Don’t use Dagger for unit testing
For testing a class with #Inject annotated constructor you don't need dagger. Instead create an instance using the constructor with fake or mock dependencies.
final class ThingDoer {
private final ThingGetter getter;
private final ThingPutter putter;
#Inject ThingDoer(ThingGetter getter, ThingPutter putter) {
this.getter = getter;
this.putter = putter;
}
String doTheThing(int howManyTimes) { /* … */ }
}
public class ThingDoerTest {
#Test
public void testDoTheThing() {
ThingDoer doer = new ThingDoer(fakeGetter, fakePutter);
assertEquals("done", doer.doTheThing(5));
}
}
Functional/integration/end-to-end testing
Functional/integration/end-to-end tests typically use the production
application, but substitute fakes[^fakes-not-mocks] for persistence,
backends, and auth systems, leaving the rest of the application to
operate normally. That approach lends itself to having one (or maybe a
small finite number) of test configurations, where the test
configuration replaces some of the bindings in the prod configuration.
You have two options here:
Option 1: Override bindings by subclassing modules
#Component(modules = {AuthModule.class, /* … */})
interface MyApplicationComponent { /* … */ }
#Module
class AuthModule {
#Provides AuthManager authManager(AuthManagerImpl impl) {
return impl;
}
}
class FakeAuthModule extends AuthModule {
#Override
AuthManager authManager(AuthManagerImpl impl) {
return new FakeAuthManager();
}
}
MyApplicationComponent testingComponent = DaggerMyApplicationComponent.builder()
.authModule(new FakeAuthModule())
.build();
Option 2: Separate component configurations
#Component(modules = {
OAuthModule.class, // real auth
FooServiceModule.class, // real backend
OtherApplicationModule.class,
/* … */ })
interface ProductionComponent {
Server server();
}
#Component(modules = {
FakeAuthModule.class, // fake auth
FakeFooServiceModule.class, // fake backend
OtherApplicationModule.class,
/* … */})
interface TestComponent extends ProductionComponent {
FakeAuthManager fakeAuthManager();
FakeFooService fakeFooService();
}
More about it in the official documentation testing page.

How can I replace Activity scoped dependencies with mocks using Dagger2

I have a scoped dependency in my Activity and I want to test that activity with some mocks. I have read about different approach that suggest to replace Application component with a test component during the test, but what I want is to replace the Activity component.
For example, I want to test the Activity against mock presenter in my MVP setup.
I believe that replacing component by calling setComponent() on Activity will not work, because Activity dependencies already injected via field injection, so during the test, real object will be used.
How can I resolve this issue? What about Dagger1? Is it has the same issue?
Injecting the Component
First, you create a static class to act as a factory for your Activity. Mine looks a little like this:
public class ActivityComponentFactory {
private static ActivityComponentFactory sInstance;
public static ActivityComponentFactory getInstance() {
if(sInstance == null) sInstance = new ActivityComponentFactory();
return sInstance;
}
#VisibleForTesting
public static void setInstance(ActivityComponentFactory instance) {
sInstance = instance;
}
private ActivityComponentFactory() {
// Singleton
}
public ActivityComponent createActivityComponent() {
return DaggerActivityComponent.create();
}
}
Then just do ActivityComponentFactory.getInstance().createActivityComponent().inject(this); inside your Activities.
For testing, you can replace the factory in your method, before the Activity is created.
Providing mocks
As #EpicPandaForce's answer makes clear, doing this the officially-supported way currently involves a lot of boilerplate and copy/pasted code. The Dagger 2 team need to provide a simpler way of partially overriding Modules.
Until they do though, here's my unnoficial way: Just extend the module.
Let's say you want to replace your ListViewPresenter with a mock. Say you have a PresenterModule which looks like this:
#Module #ActivityScope
public class PresenterModule {
#ActivityScope
public ListViewPresenter provideListViewPresenter() {
return new ListViewPresenter();
}
#ActivityScope
public SomeOtherPresenter provideSomeOtherPresenter() {
return new SomeOtherPresenter();
}
}
You can just do this in your test setup:
ActivityComponentFactory.setInstance(new ActivityComponentFactory() {
#Override
public ActivityComponent createActivityComponent() {
return DaggerActivityComponent.builder()
.presenterModule(new PresenterModule() {
#Override
public ListViewPresenter provideListViewPresenter() {
// Note you don't have to use Mockito, it's just what I use
return Mockito.mock(ListViewPresenter.class);
}
})
.build();
}
});
...and it just works!
Note that you don't have to include the #Provides annotation on the #Override method. In fact, if you do then the Dagger 2 code generation will fail.
This works because the Modules are just simple factories - the generated Component classes take care of caching instances of scoped instances. The #Scope annotations are used by the code generator, but are irrelevant at runtime.
You cannot override modules in Dagger2 [EDIT: you can, just don't specify the #Provides annotation on the mock), which would obviously be the proper solution: just use the builder().somethingModule(new MockSomethingModule()).build() and be done with it!
If you thought mocking is not possible, then I would have seen two possible solutions to this problem. You can either use the modules to contain a pluggable "provider" that can have its implementation changed (I don't favor this because it's just too verbose!)
public interface SomethingProvider {
Something something(Context context);
}
#Module
public class SomethingModule {
private SomethingProvider somethingProvider;
public SomethingModule(SomethingProvider somethingProvider) {
this.somethingProvider = somethingProvider;
}
#Provides
#Singleton
public Something something(Context context) {
return somethingProvider.something(context);
}
}
public class ProdSomethingProvider implements SomethingProvider {
public Something something(Context context) {
return new SomethingImpl(context);
}
}
public class TestSomethingProvider implements SomethingProvider {
public Something something(Context context) {
return new MockSomethingImpl(context);
}
}
SomethingComponent somethingComponent = DaggerSomethingComponent.builder()
.somethingModule(new SomethingModule(new ProdSomethingProvider()))
.build();
Or you can bring the provided classes and injection targets out into their own "metacomponent" interface, which your ApplicationComponent and your TestApplicationComponent extend from.
public interface MetaApplicationComponent {
Something something();
void inject(MainActivity mainActivity);
}
#Component(modules={SomethingModule.class})
#Singleton
public interface ApplicationComponent extends MetaApplicationComponent {
}
#Component(modules={MockSomethingModule.class})
#Singleton
public interface MockApplicationComponent extends MetaApplicationComponent {
}
The third solution is to just extend the modules like in #vaughandroid 's answer. Refer to that, that is the proper way of doing it.
As for activity scoped components... same thing as I mentioned here, it's just a different scope, really.
I've found the following post that solves the problem:
http://blog.sqisland.com/2015/04/dagger-2-espresso-2-mockito.html
You need first to allow to modify the component of the activity:
#Override public void onCreate() {
super.onCreate();
if (component == null) {
component = DaggerDemoApplication_ApplicationComponent
.builder()
.clockModule(new ClockModule())
.build();
}
}
public void setComponent(DemoComponent component) {
this.component = component;
}
public DemoComponent component() {
return component;
}
And modify it in the test case
#Before
public void setUp() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
DemoApplication app
= (DemoApplication) instrumentation.getTargetContext().getApplicationContext();
TestComponent component = DaggerMainActivityTest_TestComponent.builder()
.mockClockModule(new MockClockModule())
.build();
app.setComponent(component);
component.inject(this);
}

Overriding debug module in tests

I have a Gradle app with a project structure similar to Jake Wharton's u2020:
/src
/androidTest
/debug
/main
/release
In my application class I build the Dagger graph and inject it:
MyApplication extends Application {
...
public void buildObjectGraphAndInject() {
Object[] modules = Modules.list(this);
mApplicationGraph = ObjectGraph.create(modules);
mApplicationGraph.inject(this);
}
...
}
Inside the debug sourceset, I define Modules.list() as:
public final class Modules {
public static Object[] list(MyApplication app) {
return new Object[] {
new AppModule(app),
new DebugAppModule()
};
}
private Modules() {
// No instances.
}
}
Inside the release sourceset, I define the same thing minus the DebugAppModule:
public final class Modules {
public static Object[] list(MyApplication app) {
return new Object[] {
new AppModule(app)
};
}
private Modules() {
// No instances.
}
}
Deeper down my dependency graph, I create a MockRestAdapter that I can use when running the debug version:
#Module(
complete = false,
library = true,
overrides = true
)
public final class DebugApiModule {
#Provides #Singleton Endpoint provideEndpoint(#ApiEndpoint StringPreference apiEndpoint) {
return Endpoints.newFixedEndpoint(apiEndpoint.get());
}
#Provides #Singleton MockRestAdapter provideMockRestAdapter(RestAdapter restAdapter, SharedPreferences preferences) {
MockRestAdapter mockRestAdapter = MockRestAdapter.from(restAdapter);
AndroidMockValuePersistence.install(mockRestAdapter, preferences);
return mockRestAdapter;
}
#Provides #Singleton MyApi provideMyApi(RestAdapter restAdapter, MockRestAdapter mockRestAdapter,
#IsMockMode boolean isMockMode, MockMyApi mockService) {
if (isMockMode) {
return mockRestAdapter.create(MyApi.class, mockService);
}
return restAdapter.create(MyApi.class);
}
}
But while I'm running tests, I would like to override the DebugApiModule with a TestApiModule that looks like this:
#Module(
complete = false,
library = true,
overrides = true
)
public final class TestApiModule {
#Provides #Singleton Endpoint provideEndpoint(#ApiEndpoint StringPreference apiEndpoint) {
return Endpoints.newFixedEndpoint(apiEndpoint.get());
}
#Provides #Singleton MockRestAdapter provideMockRestAdapter(RestAdapter restAdapter, SharedPreferences preferences) {
MockRestAdapter mockRestAdapter = MockRestAdapter.from(restAdapter);
mockRestAdapter.setDelay(0);
mockRestAdapter.setErrorPercentage(0);
mockRestAdapter.setVariancePercentage(0);
return mockRestAdapter;
}
#Provides #Singleton MyApi provideMyApi(MockRestAdapter mockRestAdapter, MockHnApi mockService) {
return mockRestAdapter.create(MyApi.class, mockService);
}
}
What's the best way to accomplish this? Do I need to create a TestAppModule like this:
public final class Modules {
public static Object[] list(MyApplication app) {
return new Object[] {
new AppModule(app),
new TestAppModule()
};
}
private Modules() {
// No instances.
}
}
And replace all of the DebugFooModule with TestFooModules? If so, how do I get around the fact that Modules.java is duplicated? Or am I way off base?
EDIT: SOLUTION
What I ended up doing is replacing the Application-level graph (where the MockRestAdapter gets created) during my test setUp
protected void setUp() throws Exception {
super.setUp();
HnApp app = HnApp.getInstance();
app.buildObjectGraphAndInject(TestModules.list(app));
getActivity();
}
What I've done this far (and I'm not entirely sure this will scale yet) is create a static test module class in my tests.
#Module(
injects = {
SharedPreferences.class
})
static class TestModule {
#Provides #Singleton SharedPreferences provideSharedPreferences(){
return Mockito.mock(SharedPreferences.class);
}
}
And in the setup() method I inject the test module
#Before
public void setUp(){
ObjectGraph.create(new TestModule()).inject(this);
}
I then #Inject the mocked class:
#Inject SharedPreferences sharedPreferences;

Right place to place injects attribute in dagger plus'ed modules

I have a doubt regarding which is the right place to set the injects attribute (not annotation) in dagger, when there are plus'ed graphs.
We have this scenario:
#Module(injects = ClassWithInjects.class, complete = false)
public final class BaseModule {
#Provides
DependencyA providesA() { return new A(); }
#Provides
DependencyB providesB() { return new B(); }
...
}
class ClassWithInjects {
#Inject
A a;
#Inject
B b;
}
that was working fine when doing:
ObjectGraph graph = ObjectGraph.create(new BaseModule()).plus(new Object[0]); // no modules used to plus by default
graph.inject(new ClassWithInjects());
Afterwards we added a new module that is the only one supposed to provide B from that moment on:
#Module(injects = ClassWithInjects.class, complete = false)
public final class BaseModule {
#Provides
DependencyA providesA() { return new A(); }
...
}
#Module(addsTo = BaseModule.class, complete = false)
public final class AdditionalModule {
#Provides
DependencyB providesB() { return new B(); }
}
class ClassWithInjects {
#Inject
A a;
#Inject
B b;
}
That is failing with
IllegalStateException No binding for B required by class
ClassWithInjects
when doing this:
ObjectGraph graph = ObjectGraph.create(new BaseModule()).plus(new AdditionalModule());
graph.inject(new ClassWithInjects());
It works when I move the
injects = ClassWithInjects.class
attribute from BaseModule to AdditionalModule.
So, where am I supposed to place the injects attribute when using plus'ed modules? Does it have to be in one of the modules used as parameters in the call to .plus(...)?
According to this github issue I have to put the injects in the module that has the bindings for the instance I try to inject dependencies into (ClassWithInjects in the example above) but, what if I have several modules providing the different bindings needed to fulfill all the dependencies of that instance? Do I have to create a module that includes all the others and put there the injects attribute?
Have you seen the Android sample here: https://github.com/square/dagger/tree/master/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs
Comparing that setup to what you have, the "injects" were defined on the Module that was plussed. I think a current limitation is that you have to define those on every plussed Module in the case where you have multiple.

Categories

Resources