Yet another MVP article — Part 5: Writing Test using a mixture of Dagger and Espresso

Written by mohsenoid | Published 2016/11/28
Tech Story Tags: android | testing | junit | mvp | yetanothermvp

TLDRvia the TL;DR App

Implementing a sample Android Application using MVP, RxJava, Dagger 2, Retrofit2, Test, and all the brand new modern methods and libraries

Previously on this article…

Yet another MVP article — Part 4: RxJava and RxAndroid know how to response_Implementing a sample Android Application using MVP, RxJava, Dagger 2, Retrofit2, Test, and all the brand new modern…_hackernoon.com

Let’s think that you have studied part1, part2, part3, and part4 which means you know everything about the sample project’s modules and structure, also get more familiar with Dagger usage in wiring up MVP layers and know the use of Retrofit for connecting to network APIs and learn how RxJava and RxAndroid benefit the project.

now let’s continue…

Test, Test, and Test… Why?

While you are working on an Application or any Software project, usually product owner comes with new ideas and features that make the project shinier! so you start to develop the way that everyone gets happy and don’t miss the deadline either, but god knows how you broke other parts of the project by adding new feature codes and changing other modules to fit your new codes.

You finish your job, run the App and check if the new feature works perfectly, and hoping that you didn’t break any thing. You release a version for QA to test and left the office as fast as possible!!!

long story short…

Counterpart!

You have spent enough time and write some tests that check all parts of your app functionality and by using a CI (continues integration) service after pushing your changes into the repo, you will get a full report of tests being passed or failed.

Come on, writing test is hard…

I believe finding the bug after 2 or 3 release is much harder to write some simple test after every feature development and code changes.

Let’s begin the Test…

according to ‘developer.android.com’:

Android Studio is designed to make testing simple. With just a few clicks, you can set up a JUnit test that runs on the local JVM or an instrumented test that runs on a device. Of course, you can also extend your test capabilities by integrating test frameworks such as Mockito to test Android API calls in your local unit tests, and Espresso or UI Automator to exercise user interaction in your instrumented tests. You can generate Espresso tests automatically using Espresso Test Recorder.

…, so the IDE supports everything for testing, stop being too lazy!

Android Studio supports 2 different types of tests:

  • JUnit Test: which is testing Java codes with no need to Android device or SDK.
  • Instrumented Test: which is testing Application functionality (usually UI reactions) most of the time using an Android device.

The point of running a test is asserting every critical point and check if it works correctly. There are different types of assertion which you will get familiar with some of them in this sample project.

Back to the sample project, we had 2 different modules, core and app. core module is pure java so every testing only happens using JUnit tests:

core module test folder

don’t forget that JUnit tests place inside the test folder inside src, beside the main folder. The packaging is the same as the main source code.

app module contains Android and Java codes, so we need both JUnit and androidTests:

app module test & androidTest folders

core module JUnit Test:

I have written a simple JUnit test “SearchInteractorTest” which test “SearchInteractor” class functionality. let’s take a look:

First of all, please remember that by keeping your test class in the same package of the class which being test, you can access everything inside that class and package without making them public to be accessible from other packages.

Secondly, in this sample, we have used mocking, which means creating a Maquette from some of the source code parts and use them the way you want. In this sample we have mocked two main classes that we don’t want them to act in a normal way:

  • MarvelApi: which handle network API calls using this line of code:

api = mock(MarvelApi.class)

  • SchedulerProvider: which provide threads for running codes using this line of code:

scheduler = mock(SchedulerProvider.class)

The next step would be creating a test result which we want the API return, which is really simple, and here is the magic of Mockito library:

when(api.getCharacters(any(String.class), any(String.class), any(String.class), any(Long.class))) .thenReturn(Observable.just(expectedResult));

The testing usually is very close to English language, so we can read it this way:

Hey jUnit, WHEN the code call the method getCharacter and passed ANYTHING as any parameters, THENRETURN a single RxJava Observable contains expectedResult.

Did you mention the @Before annotation at the beginning of the setup method? JUnit test would run this method before any method with @Test annotation, then prepare whatever you require for your test.

app module Tests:

As the app module holds the View layer of MVP inside, almost every Test is about the UI functionality.

I have used two different UI functionality test libraries in this sample project:

Robolectric:

Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds.

which in a simple way means, throw away the slow useless emulator!! I will run the test and guess the UI changes by myself.

Espresso:

Espresso tests run optimally fast! It lets you leave your waits, syncs, sleeps, and polls behind while it manipulates and asserts on the application UI when it is at rest.

which uses an Android device or emulator to run the tests, and being supported by Google.

All Android developers know that UI testing is always a big trouble, so Google in the last I/O introduced Espresso Test Recorder which makes everything easy for UI testing and assertions.

Sample UI Test using Robolectric?

Take a look at test class code:

What’s going on?!

  • @RunWith annotation: tell the IDE which class will run this test Class
  • @Config annotation: is a part of the Robolectric library and configure the test environment.
  • shadows: are helping classes that plug to Robolectric and make available testing new features like Snackbar.

After that, as I mentioned before in setup method we prepare what ever is required for tests, and then the Tests methods which I think are really simple to understand!

Do not forget that running this test is really simple and there is no need to emulator! It is also located inside test folder (jUnit test position!) which means it is not androidTest.

Sample UI Test using espresso:

I believe one of the perfect places that you will get the result for all of your efforts writing your code using MVP will show up in UI tests using espresso.

You are not in charge for testing the API calls results when writing a test for your app, so there is no need to call network. Using some tricks with Dagger you will inject everywhere the mocked API module!!!

let’s explain a little more about mocking with Dagger:

first of all, take a look at app build.gradle file and find this line of code:

/* replaced with custom MockTestRunner */testInstrumentationRunner "com.mirhoseini.marvel.MarvelTestRunner"

this is the class “AndroidJUnitRunner” which has been replaced with e custom Test Runner.

What’s inside MarvelTestRunner?

The point of this class is replacing the MarvelApplication class with MarvelTestApplication:

This class extends MarvelApplicationImpl class which means it contains whatever inside, but replace the createComponent method and use ApiTestModule with the regular one.

This is the way Dagger will inject mocked API class where ever it is required.

and this is the MainActivityTest UI functionality Test:

TL;DR:

We decouple our source code into different layers of MVP to make it simple to read and maintain. New libraries like Retrofit and RxJava helps us in this regard. We try to write a clean code, and for a happy ending, all these efforts show up when you want to write a test without taking care of network connection or API calls result to test UI or another part of your code functionality.

In the near future when you want to add a new feature, you will benefit all of these efforts and everyone will be happy. :)

That’s a wrap

Please clone the project repo from GitHub and let me know if you think we can improve this sample project.

I look forward to your pull requests and comments.

Share this article if you think it is useful, and follow me for more articles Mohsen Mirhoseini.

Mohsen Mirhoseini - Senior Android Developer_I am a senior Android Developer with about nine years experience in the field of Computer Software engineering. I have…_mirhoseini.info


Written by mohsenoid | Senior Android Developer
Published by HackerNoon on 2016/11/28