I used to work in MVP and I usually test my presenters using a plain Junit (Not the Instrumentation !) , since Presenters only have the business logic and no references to Android internals whatsoever.
Now by switching to Dagger 2 , I understood that I have a problem setting up a "TestModule" for my app component.
Creating a component will not work from within a test class (probably because "apt" is not running there)
Didn't find any examples for using Dagger with a standard Junit testing. Every example I have found only relies on Instrumentation testing or Roboelectric (which basically mocks Activities and other Android related stuff) , but this is just a UI testing for me , and I don't need that.
Just to make things clear , I am talking about the tests that are located at app->src->test folder not the app->src->androidTest !
So do I do something wrong ? Or missing something ? Can anyone explain or give examples on how to use Dagger 2 in normal unit tests ?
I'm not sure if my solution will work for you but I see no reason it shouldn't.
First I created testInjectionComponent
#Singleton
#Component(modules = {MockNetworkModule.class})
public interface MockInjectionComponent extends InjectionComponent {
void inject(DaggerUnitTest daggerUnitTest);
}
Then my Unit Tests I add injection in the before method. like so:
#Before
public void setUp() throws Exception {
MockInjectionComponent mockInjectionComponent = DaggerMockInjectionComponent
.builder()
.mockNetworkModule(new MockNetworkModule())
.build();
mockInjectionComponent.inject(this);
}
Then I just Annotate my Injected Object.
EDIT :
Do not forget to add testApt "com.google.dagger:dagger-compiler:$daggerVersion" at your app.gradle file .
As mentioned by the accepted answer. Do not forget to add :
For Java
Android Test
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:$dagger_version'
JUnit test
testAnnotationProcessor 'com.google.dagger:dagger-compiler:$dagger_version'
For Kotlin
Android Test
kaptAndroidTest 'com.google.dagger:dagger-compiler:$dagger_version'
JUnit test
kaptTest 'com.google.dagger:dagger-compiler:$dagger_version'
You don't need any dagger to test your presenter. Dagger's job is it to fullfill the dependencies of your classes (dependency injection).
For example you have this Presenter:
public class MyPresenter {
Database database;
ApiService apiService;
#Inject
public MyPresenter(final Database database, final ApiService apiService) {
this.database = database;
this.apiService = apiService;
}
}
Dagger will provide your Presenter with the database and apiService objects for your presenter to use them. When running the actual app (not a test) these will be real objects with real functionality.
When testing the presenter, you want to test only the presenter, everything else should be mocked.
So when you create the presenter in your PresenterTest, you create it with mocked versions of database and apiService.
You can then test how your presenter interacts with these object by
a. mocking the objects behaviour like
when(database.getSomething()).thenReturn(something)
b. verify your presenter does what you want it to do with these objects like
verify(database).saveSomething()
(pseudo code)
Standard way to mock would be Mockito.
You can swap out real modules with fake modules in two ways: do it at compile time using flavors as recommended by google architecture samples or at runtime by creating an abstract method which injects the real thing in production code and fake dependencies in test code. In the second case your test has to subclass the class that you want to mock and build the component from scrach
Related
So I am currently in the process of learning dagger 2, and from the tutorials that I've read so far, for a dependency to be injected, the #Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work, or if I don't want other parts of the code to know that dagger exists.
The application structure I have at the moment is:
App Module - where I'd like to put my DI code in (e.g. dagger modules, etc).
Presentation Module - Views/ViewModels etc.
Domain Module - Use Cases etc.
Data Module - Repositories etc.
With pretty much this style of classes contained in my application:
class ExampleViewModelImpl(useCase: ExampleUseCase): ViewModel() in Presentation (gets initialised from an Activity or similar).
class ExampleUseCaseImpl(repository: ExampleRepository): ExampleUseCase in Domain
class ExampleRepositoryImpl(dao: ExampleDao): ExampleRepository in Data
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible? Code examples of how this is achieved would be great.
I am unsure of some terminologies, and wasn't able to find a solution online. If there are good resources which explains what I'm asking, that would also be great.
if I don't want other parts of the code to know that dagger exists.
#Inject is a standard (JSR 330) which Dagger implements. Adding those annotations doesn't have anything to do with Dagger and can be used the same way with other DI frameworks. If it's your code you should just add those #Inject annotations where appropriate. Think of them as documentation: What constructor/field/method must be injected to create & use this object?
The only place where your classes will know that Dagger exists is at the same place where you'd be creating the objects otherwise, too.
Going down that path, of course you could use Dagger without any #Inject annotations, but you'd be writing a lot of unnecessary boilerplate and missing out on the most powerful feature of Dagger at the same time (code generation).
#Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work
That's what #BindsInstance with the #Component.Builder is for (add an object to the component) and what #Provides annotated methods are for (create and initialize an object from a module)
If you really want to write code without #Inject, then you'd do exactly this for all of your objects. This means a lot of modules, and even more #Provides annotated methods. It will work, but I don't see the point in writing all those methods if a single #Inject on the constructor has the same effect.
In my opinion the best thing about Dagger is that I can add / remove / change constructor parameters and don't have to touch any other parts of my code since Dagger will generate new code with the new arguments. In your case you'd have to also change the parameters to the #Provides method as well as the constructor invocation.
Next let's look at how to remove #Inject from fields. Basically you don't want to do field injection, so instead of writing an injection method in the component, you'd write provision methods.
#Component
class MyComponent {
fun inject(activity: MyActivity)
}
class MyActivity {
#Inject lateinit var myDep: Dependency
fun onCreate() {
component.inject(this)
}
}
Removing the #Inject we need to use the provision methods instead.
#Component
class MyComponent {
fun provisionMyDependency() : Dependency
}
class MyActivity {
lateinit var myDep: Dependency
fun onCreate() {
myDep = component.provisionMyDependency()
}
}
It will work and everything, but again, you will miss out on the single best feature of Dagger: Code generation. The example above looks alright because I only added a single dependency, but think about what happens to those 2 different implementations when you add / remove / change dependencies, how well it will scale. If you prefer to do things manually any refactoring will become arduous.
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible?
Your question (especially the title) is in direct conflict with your goal. If you don't want to use those annotations, then you can't use Dagger code generation & injection but have to resort to do it manually as highlighted above.
with as much automated dependency injection as possible
To best utilize Dagger you add #Inject on the constructor and/or fields of every class that should end up on your dependency graph and let Dagger do its thing.
I cannot get my head around how to setup a couple of things when porting the code from Dagger 2 to Android Dagger 2.11. In Dagger 2 the setup was something like this:
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
this.initializeInjector();
}
private void initializeInjector() {
//this class should be auto-generated by Dagger on build
this.applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.netModule(new NetModule())
.build();
}
public ApplicationComponent getApplicationComponent() {
return this.applicationComponent;
}
}
You then had access to the applicationComponent and you could inject any object by using the:
getApplicationComponent().inject(MyCustomObject);
In Android Dagger 2.11 you don't do that anymore. For Activities and Fragments you can inject with the AndroidInjector.inject() method but what about other types? Let's look at an example below. We have a JobManager that can post jobs. The jobs are persisted to a file and when they should be posted they are first deserialized. The problem is that its dependencies are not set of course. So the question is: How to do that?
public class JobManager {
private Context context;
#Inject
public JobManager(Context context) {
this.context = context;
}
public void postJob(String jobId) {
MyJob myJob = deserializePersistedJobFromFile(jobId);
//((App) context).getApplicationComponent().inject(myJob); //This was the old way of doing injection
AndroidInjector.inject(myJob); //This doesn't work - what to do now?
}
.
.
.
}
public class MyJob {
#Inject
ApiService apiService;
.
.
.
}
You can get Dagger to inject a MembersInjector<T> and then use that to inject dependencies into your own objects...
public class JobManager {
private Context context;
#Inject
public JobManager(Context context, MembersInjector<MyJob> jobInjector) {
this.context = context;
}
public void postJob(String jobId) {
MyJob myJob = deserializePersistedJobFromFile(jobId);
jobInjector.inject(myJob);
}
.
.
.
}
Is there any problem you experience with the "old" approach that makes you want to move to the "new" one?
I couldn't find one single real advantage in performing dependency injection using the static AndroidInjector class, but it does increase the complexity of the code.
Therefore, if you don't have a very specific reason to move in that direction, I would suggest to stay with the "old" working approach.
As for injection into non-Activity/Fragment classes, I think you shouldn't use DI framework for this. Use Dagger for injection into Application, Activity, Fragment and Service only. More information available in this post: Dependency Injection in Android.
Writing this on a phone so apologies for any typos.
TL;DR Would it not make sense that, MyJob needs an #Inject(ed) constructor that takes the ApiService, rather than a member injection? Is there a reason why MyJob can't have it's own constructor? (Unfamiliar if this is an Android SDK class or not). If that's not the answer then I have another observation that your JobManager seems to do what the JobScheduler does? Unless it's simply a confusion of terms (i.e. both "jobs")
Outside of Android and it's lifecycle uniqueness dependency inversion's most common use is constructor injection. Learning the DI pattern within the Android framework isn't the best introduction and you get caught up in the 'lying to the complier' DI framework functionality that is meant to simply help move off a legacy codebase (c.f. Dagger 1's static injection or Guide's 'private' member injection).
As a side note, I have avoided moving to "Android Dagger" since it seems to go against having modular separation of code. I think I have more to learn here but right now the boilerplate distruption advantage of "Android Dagger" is outweighed by my need for loosely coupled feature modules to support Instant Apps and an altogether more modular code base.
Hope that helps a bit.
I wrote this article which should be helpful to you. It links to the sample code on Github.
https://proandroiddev.com/exploring-the-new-dagger-android-module-9eb6075f1a46
Pay close attention to the AppModule and how it keeps track of the application so you can pass application.getApplicationContext() into constructors for your JobManager
Using dagger android library has advantages :
1) Using dagger violates dependency injection principle that classes shouldn't know about how dependencies are injected, this violation can be fixed using dagger android library
2) Dagger code can be decoupled from android components.
3) Clean code can be achieved as you don't need to initialize dagger components and call inject methods in android components, leading to creation of easy to maintain apps.
You can decouple dagger from android using dagger android components such as DaggerActivity,DaggerApplication, and DaggerFragment and moving AndroidInjection.inject() calls to central location, instead of calling in each and every activity and fragment, by using activity lifecycle callback on application.
You can read detailed explanation about dagger android at
http://www.zoftino.com/android-framework-classes-dependency-injection-using-dagger-android
I want my code to be testable and flexible and I cannot make a choice whether I need to pass all dependencies explicitly to a constructor of a presenter or it's better to pass only View interface to a constructor and inject all dependencies in it.
It is a desirable pattern.
Every time you have access to object constructor, you should inject dependencies in constructor or other methods. #Inject annotation is indended mainly to be used inside object, that are not created by you.
When injecting all dependencies in constructor, during tests you pass all your dependencies to your model during initialisation. Therefore every test might contain different dependencies and different instance of created class. That is also the aim of unit tests - provide a sandbox for every test.
It is also easier to mock dependencies with Mockito.
Remember, that in unit tests, you don't have dependency any framework configured. A unit test usually contains created model and nothing more. Everything must be created by you (or mocked by framework)
Here is a sample unit test that proves the statement above:
#RunWith(MockitoJUnitRunner.class)
public class GetAreasUseCaseTest {
#Mock ApiManager mApiManager;
#Mock DatabaseManager mDatabaseManager;
private GetAreasUseCase mGetAreasUseCase;
#Rule
public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule();
#Before
public void setUp() {
mGetAreasUseCase = new GetAreasUseCase(mApiManager,
mDatabaseManager);
doReturn(Observable.empty())
.when(mDatabaseManager)
.insertAreas(any(Area.class));
}
#Test
public void testGetAreasUseCaseApiInteraction() throws Exception {
TestSubscriber<List<Area>> testSubscriber = new TestSubscriber<>();
setCorrectApiResponse();
boolean input = true;
Observable testedObservable = mGetAreasUseCase.build(input);
testedObservable.subscribe(testSubscriber);
verify(mApiManager).getAreas(anyLong());
}
}
As you can see the structure of the test is very clear. It is well known, what is mocked and which object is tested. You have the control of the behaviour of dependencies.
If you plan to do only instrumentation tests, then you are provided with the ApplicationContext in tests and Dagger is properly initialised. There is no difference here. Of course you might still emulate Module's and Component's behaviour and provide custom object's Mocks instead of real classes (Example)
its not a bad practice but its hard to change the code in later changes. what if you want to add a new dependency for presenter ? then you have to change almost everything in your code.
what you are going to do actually is called Dependency Injection and the best practice is to do Dependency Injection, is using libraries like Dagger.
i think Dagger is the most powerful Dependency Injection library up to now. you will write some methods for providing your dependencies and Dagger will provide them for you whenever you want them using a #inject Annotation. for a complete instruction see this link:
http://www.vogella.com/tutorials/Dagger/article.html
I'm currently developing an Android MVP Application, and I'm trying to separate my dependencies in different Dagger2 Modules.
The problem I'm having is about changing a module in Unit Test Time. The scenario is the following:
LoginComponent, which uses two modules: LoginModule and HTTPModule
LoginModule in one of its methods requires an OkHttp instance, which is provided by HTTPModule.
The code is the following:
#Singleton
#Component(modules = {LoginModule.class, HTTPModule.class})
public interface LoginComponent {
}
#Module(includes = {HTTPModule.class})
public class LoginModule {
#Provides
#Singleton
public MyThing provideMyThing(OkHttpClient client) {
// Do things with it
}
}
#Module
public class HTTPModule {
#Provides
#Singleton
public OkHttpClient provideOkHttpClient(){
// Return the OkHttpClient
}
}
The thing is, at test time I would need to change the OkHttpClient that is returned (by making it accept all the certificates, as when I run it on the JVM it does not accept the LetsEncrypt certificate).
Also I would need that because I need to declare that MyTest.class can be injected with module, and as MyTest.class is under the app/src/test/ folder, it's not visible for the classes that are placed under app/src/main/. What I've done until now is to copy and paste the Component and the modules to the /test/ folder, and make the injected class declaration there. But I know there must be a proper way to achieve what I'm looking for.
Another thing I've tried is annotating the methods with custom Scopes (creating a #TestScope annotation). However this leads me to the same problem that I had commented before: I cannot make the MyTest.class visible to the component, because it's placed under the /test/ folder.
I've already checked other similar questions, such as this one and this another one, but this last one is for running tests with Robolectric, and by now I'm able to unit test most of my code with JUnit4 only (Android Studio 2-Beta 8).
If anyone could point me to the right direction, I would be more than grateful.
Thanks in advance!
You're using Dependency injection in a way that still keeps your code tightly coupled. Generally speaking you want your dependencies to be interfaces instead of actual classes. This keeps your code nice and loose, easy to read, modify and maintain.
Hide your network operations behind an interface to allow you to modify the network implementation whenever you need to. This could be done for testing - in your case, but it will also allow you to switch out the network library if you'll want to or need to in the future without changing any other code.
Try something like this:
#Module
public class HTTPModule {
#Provides
#Singleton
public NetworkProvider provideNetworkProvider(){
// Return the Network provider
}
}
The network abstraction layer:
public interface NetworkProvider {
// Methods to send requests and receive async responses
}
The OkHttp implementation:
public class OkHttpNetworkProvider implements NetworkProvider {
// Implement NetworkProvider. This is the only class that
// knows about OkHttp and its components
}
Now you can create a mock version of NetworkProvider and use it for testing, whether via a test module or directly.
I use Dagger2 in my android app.
Basically I inject a HttpClient (interface) in MainActivity.
#Module
public class MainActivityModule{
#Provides public HttpClient providesHttpComponent(){
return new RealHttpClient();
}
}
#Component( modules = MainActivityModule.class )
public interface MainActivityComponent {
public MainActivity injectActivity(MainActivity);
}
public class MainActivity extends Activity {
public void onCreate(Bundle saved){
super.onCreate();
injectDependencies();
}
protected void injectDependencies(){
Dagger_MainActivityComponent
.builder()
.mainActivityComponent( new MainActivityModule())
.build()
.injectActivity(this);
}
}
So far so good, that works like expected. Now I want to write some unit tests (not android instrumentation tests) for MainActivity where I want to use TestMainActivityModule instead of MainActivityModule.
#Module (overrides = true )
public class TestMainActivtiyModule extends MainActivityModule {
#Provides public HttpClient(){
return new MockHttpClient();
}
}
My question is: How do I force MainActivity to use TestMainActivitiyModule instead of MainActivityModule? Is there a good solution for that?
My current approach is to use inheritance and to override getModule(), something like this
public class TestMainActivity extend MainActivity {
#Override
protected void injectDependencies(){
Dagger_MainActivityComponent
.builder()
.mainActivityComponent( new TestMainActivtiyModule())
.build()
.injectActivity(this);
}
}
and to run unit test against TestMainActivity instead of MainActivity.
I guess it works, but one of the problems I'm facing with this approach is that I can't start TestMainActivity with an Intent because I can't specify it in AndroidManifest.xml
Does anyone know a better approach for unit testing with dagger2 on android?
The approach I've started using has involved maintaining two modules (one for the app, one for testing) in parallel build variants (ex: app and integration). Still not sure how well that solution scales so YMMV. I'd be very happy to see a better solution!
This is also a great read: http://engineering.circle.com/instrumentation-testing-with-dagger-mockito-and-espresso/
I would really suggest you to check this boilerplate since it is fully based on DI using Dagger2. It also shows how you can replace your dependencies in the test environment in a very neat way.
The dependencies currently handled by the boiler plate are the following:
Database dependency: encapsulates all the database operations.
Shared preferences dependency: deals with shared preferences.
Local files dependency: which deals with saving on files.
Analytics dependency: covers all the operation of reporting events to your analytics backend (GA, Segment, FB, Flurry ..)
Logging dependency: encapsulates all the operations related to logging to your console
Api dependency: encapsulates all the API related operations
The power of dependency injection comes really handy especially for testing since you can easily switch your dependencies in the test environment to dummy dependencies.