Dagger Field Injection Testing - android

I am using Dagger 2 and have a few issues with generate singleton providers in the module when implementing tests for my class.
class SomeContentProvider extends ContentProvider {
// this should be normal foo if run by application,
// or mocked foo if run by tests
#Inject Foo foo;
public Provider() {
Component.getComponent().inject(this);
}
}
#Module
class ProviderModule {
#Singleton
#Provides
Foo providesFoo() {
returns new Foo();
}
}
#Module
class ProviderTestModule {
#Singleton
#Provides
Foo providesFoo() {
returns Mockito.mock(Foo.class);
}
}
public class SomeContentProviderTests extends InstrumentationTestCase {
#Inject Foo foo; // this should be mocked Foo
#Override
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
Component.getTestComponent().inject(this);
}
public void test1() {
// needs new instance of Foo when test1 is run from SomeContentProvider
}
public void test2() {
// needs another new instance of Foo when test2 is run from SomeContentProvider
}
}
So I have 2 questions.
I cannot use constructor injection as ContentProvider has a default constructor. How does SomeContentProvider get the Foo from the the test module?
In test1 and test2, how do I ensure that a new instance of Foo is created when each test is being run?
Thanks!

I found this post especially useful for me. Though the particular problem I am have is much more convoluted - but I had used the same idea to mock the module's provider.
How do you override a module/dependency in a unit test with Dagger 2.0?

You should use the #Named annotation for identify which dependency you want to inject if you have more than one dependency of same type.
See docs for more details: https://google.github.io/dagger/users-guide#qualifiers

Related

Difference between the #Singleton in module and #Singleton in component in Dagger 2

Im learning Dagger 2, i have noticed that in some examples there is a #Singleton in the module's methods and on other #Singleton on the Component's methods? What is the difference and what exactly a #Singleton annotation on a module's method and on an component's method mean?
Since you're a beginner, I highly recommend just trying stuff. Writing unit tests is easy enough, and it helps to understand and prove theories.
If you didn't already, read the User's Guide for some basic knowledge about dagger and scopes.
Annotating methods in components (provision methods) doesn't have any effect. You will have to annotate the class or providing method in a module. I want to quickly show how you can just quickly prove this yourself:
We have 2 Component, one using a scope #Singleton, the other one none:
#Singleton
#Component(modules = SingletonModule.class)
public interface SingletonComponent {
Object getObject();
}
#Component(modules = NormalModule.class)
public interface NormalComponent {
#Singleton
Object getObject();
}
With those components come 2 modules, one providing the singleton scoped object (same as the component) the other one just uses no scope:
#Module
public class SingletonModule {
#Provides
#Singleton
public Object provideObject() {
return new Object();
}
}
#Module
public class NormalModule {
#Provides
public Object provideObject() {
return new Object();
}
}
And now we just create a small test:
public class ComponentTest {
#Test
public void testSingletonComponent() {
SingletonComponent component = DaggerSingletonComponent.create();
Assert.assertEquals(component.getObject(), component.getObject());
}
#Test
public void testNormalComponent() {
NormalComponent component = DaggerNormalComponent.create();
Assert.assertNotSame(component.getObject(), component.getObject());
}
}
This test will succeed and prove that annotating methods in components doesn't do anything. Scoping objects in modules, or annotating the class itself when using constructor injection will result in the object being reused within the same scope / the same component.
Creating 2 components of the same scope will also lead to duplicate objects, as can be proven like this:
#Test
public void testTwoSingleonComponents() {
SingletonComponent component1 = DaggerSingletonComponent.create();
SingletonComponent component2 = DaggerSingletonComponent.create();
Assert.assertNotSame(component1.getObject(), component2.getObject());
}
Be sure to read some tutorials and be sure to try things out. The compiler will complain if you do things wrong! :)

What does #Module means in dagger for android?

I have read many blogs but still i am not able to figure out #Module annotation functioning in dagger.
#Inject i got that it provides dependency injection at runtime. But what does #Module does.
since the object graph is also built on module.
For ex i.e i have this snippet of code from https://github.com/AndroidBootstrap/android-bootstrap.
#Module(
complete = false,
injects = {
BootstrapApplication.class,
BootstrapAuthenticatorActivity.class,
MainActivity.class,
BootstrapTimerActivity.class,
}
)
public class BootstrapModule {
}
so what does it basically does. since i am also trying to build one application using dagger as dependency injection for android.But since I am not able to get #Module concept clearly I am just stuck.
Can anyone please help me out with some basic example or concept. I think this will be helpful for all who is using dagger.
If you have a look to the docs for the annotation, a #Module annotated class defines a class that contributes to the dagger object graph. In the Spring framework for example, the equivalent would be the #Configuration anntotation. It defines a configuration point for your object graph, where you declare which objects you want to be available for injection and their scopes.
As a simple example, let's say we want a singleton object to be used by any Activity in the app. It has to be created in the module:
#dagger.Module(injects = {MyActivity.class})
public class Module {
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean();
}
}
This will create a MySingleton object which can be injected in MyActivity. This is a very basic example, but we can perform other actions in the graph there, like using dependencies in the constructors:
#dagger.Module(injects = {MyActivity.class})
public class Module {
private DependencyBean dependency = new DependencyBean();
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean(dependency);
}
#Provides
#Singleton
public MySinletonBean provideMyOtherSingleton() {
return new MyOtherSinletonBean(dependency);
}
}
Then, in MyActivity we need to access the graph for the application in the onCreate method:
#Inject
MySingletonBean singleton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
((MyApplication) getApplication()).getGraph().inject(this);
}
So, who does create the object graph here? The MyApplication class does it when your application starts (don't forger to add it in your androidManifest.xml):
public class MyApplication extends Application {
private ObjectGraph graph;
public ObjectGraph getGraph() {
return graph;
}
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new Module(this));
graph.inject(this);
}
}
So the execution flow in a dagger app would be:
The android app starts and the MyApplication class builds the graph, parsing the #Module annotated classes and keeping an instance of it.
Then, the classes declared in the module can access its objects just injecting themselves in the object graph. Gradle then will evaluate their #Inject annotations and perform the dependency injections.
I guess Annotation Processing Tool requires that to generate code at the compile time.
This makes it Dagger can provide validation at compile time and not only at runtime.

Dagger not initializing injected field in Android

Started introducing Dagger into my App and I'm having problems getting a very basic field initialized. Here's a reduced version of my code:
#Inject public DaggerUtils daggerUtils;
public class AppState extends Application {
#Override
public void onCreate() {
super.onCreate();
// Set up Dagger
AppModule appModule = new AppModule();
mObjectGraph.create(appModule);
daggerUtils.print();
}
}
Module used:
#Module(
injects = { AppState.class}
)
public class AppModule {
// This provides method is commented out because from what I can understand from the Dagger documentation
// Dagger should automatically take care of calling the constructor I have provided
// with the #Inject annotation. I have tried commenting this out as well and it still
// fails.
//#Provides
//DaggerUtils provideDaggerUtils() {
// return new DaggerUtils();
//}
}
Basic util class:
public class DaggerUtils {
#Inject
public DaggerUtils() {
}
public void print(){
Logger.e("Dagger", "printed instantiated");
}
}
So from what I understand because I have the #Inject annotation before the DaggerUtils constructor and the #Inject annotation before the DaggerUtils instance I'm using in my AppState class, Dagger should take care of initializing the DaggerUtils instance without me having to call the constructor. However it keeps giving me an NullPointerException when I try to call daggerUtils.print() (Line 12 in AppState class). Why is dagger not initializing DaggerUtils? I feel like I'm missing something very basic here. I've also tried using the #Provides method commented out in the AppModule to provide an instantiated DaggerUtils but it still isn't working.
I had same problem this evening.
For every class, who needs injection you must call:
mObjectGraph.create(appModule).inject(this);
That is usefull to create inject method in Application.
public void inject(Object object) {
mObjectGraph.inject(object);
}

Replacing Provider injections with Mockito mocks during test with Dagger

I am attempting to test-drive a suite of changes I'm making to my Android service (android.app.Service) - I am using Dagger and Robolectric and I need to replace the field injected classes within the service with some mocks to reduce the test scope...make it (slightly) more 'unit' like.
So, the short version...
I inject Providers.of (Guice syntax there...) into my android.app.Service. How do I replace them with MockProviders during a unit test?
The longer version...
This is what the relevant service code looks like;
#Inject SpotService spotService;
#Inject Provider<SynchroniseTidePosition> syncTidePosition;
#Inject Provider<SynchroniseSwellDataTask> syncBuoyData;
#Inject Provider<SynchroniseConditionsTask> syncConditionsData;
#Inject SpotRatingCalculator spotRatingCalculator;
#Inject LocalBroadcastManager localBroadcastManager;
#Inject NotificationManager notificationManager;
/**
* #see android.app.Service#onCreate()
*/
#Override
public void onCreate() {
super.onCreate();
inject(this);
...
So, under normal operation the startService(intent) call lets the service inject it's dependencies during onCreate and we're all good.
Under my test I want to replace the injected Providers get() calls with Mockito mocks. I have attempted to follow the Dagger test example and created a test module that looks like this;
#Module(includes = OceanLifeModule.class,
injects = {TestSynchronisationServiceNotifications.class},
overrides = true)
static class TestSynchronisationServiceNotificationsModule {
#Provides LocalBroadcastManager provideLocalBroadcastManager() {
return LocalBroadcastManager.getInstance(Robolectric.application);
}
#Provides NotificationManager providesNotificationManager() {
return (NotificationManager) Robolectric.application.getSystemService(Context.NOTIFICATION_SERVICE);
}
#Provides SpotService provideSpotService() {
return mock(SpotService.class);
}
#Provides SpotRatingCalculator provideSpotRatingCalculator() {
return mock(SpotRatingCalculator.class);
}
#Provides SynchroniseTidePosition provideSyncTidePosition() {
return mock(SynchroniseTidePosition.class);
}
#Provides SynchroniseConditionsTask provideSyncConditionsTask() {
return mock(SynchroniseConditionsTask.class);
}
#Provides SynchroniseSwellDataTask provideSyncSwellDataTask() {
return mock(SynchroniseSwellDataTask.class);
}
}
I am expecting that when my actual Service code calls the Provider get() I would be getting the Mockito mocks back (those are the mocks that my test module #Provides).
This isn't happening. What's wrong with the approach I'm heading down here?
Make your own Providers.of():
public static <T> Provider<T> of(final T t) {
return new Provider<T>() {
public T get() {
return t;
}
}
}
Dagger should probably include this in a testing module.

Dagger throw a NoSuchMethodException when creating the graph

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.

Categories

Resources