Android Unit Testing Part III: Disintegration
This is the third of a four part series on Android Unit Testing. In the last two articles I discussed the general principles of having good tests and the way to run Android tests on JVM making them fast. This part will show how to make your Android code less heavily coupled. This is a preparation step to ensure that your tests are isolated from each other.
We want to test each unit of work separately to make sure that each piece of our machinery is working properly. We need to be able to inject all dependencies into classes under the test (instead of this class instantiating a production dependency). I am not a fan of manual dependency injection (i.e., passing them through a constructor or setters). Such a manual method requires a lot of code and drags all dependencies through multiple classes to inject them into the end class.
There are a lot of dependency injection frameworks for Android out there: Dagger, RoboGuice, SpringAndroid, Guice, and Transfuse are a few. I won’t go into a detailed comparison, but I like Dagger the most because it provides compile time injection, and doesn’t influence runtime (specifically startup time) too much.
Again, here there are detailed tutorials at the end of this post and my summary is below:
My Summary
-
Modify the application Gradle file
Add the following code under the dependency section:
compile 'com.squareup.dagger:dagger:1.2.1' provided 'com.squareup.dagger:dagger-compiler:1.2.1'
-
Modify the manifest
Add the following code to the Application tags:
android:name=".MyApplication"
-
Create the classes
Add the
MyApplication
class.public class MyApplication extends Application { private ObjectGraph applicationGraph; @Override public void onCreate() { super.onCreate(); applicationGraph = ObjectGraph.create(getModules().toArray()); } protected List<Object> getModules() { return Arrays.<Object>asList( new MyModule(this) ); } public void inject(Object object) { applicationGraph.inject(object); } }
-
Add the
MyModule
class.package com.example.myapplication; import dagger.Module; import dagger.Provides; @Module( injects = { MainActivity.class } ) public class MyModule { private final MyApplication application; public MyModule(MyApplication application) { this.application = application; } }
-
Modify
MainActivity
and replace codeprivate Foo foo = new Foo();
with:@Inject Foo foo;
and add following code to
onCreate()
:// This will inject all @Inject members // recursively for everything what is marked as @Inject ((MyApplication)getApplicationContext()).inject(this);
-
Modify the
Foo
class and replace codeBar bar = new Bar();
with:@Inject Bar bar;
Modify Bar class and add
@Inject Bar() { }
Now, instances of Foo
and Bar
are
automatically injected in the runtime. However, your test will fail
with NPE, because the Foo class has a Bar dependency which wasn’t
delivered. I.e., we don’t want it injected by Dagger -— we want mocked
dependency, not a real one.
Resources
Stay tuned for the final part of our series, where I will show you how to make tests isolated. You can also check out the full code at GitHub.
Okta Developer Blog Comment Policy
We welcome relevant and respectful comments. Off-topic comments may be removed.