How to be a Mock-Star…😎

In this article we will go through the transformation of an ordinary Android developer into a 😎MockStar😎. We will see how she was forced to write tests which made her use testing tools like Mockito to make her life easier and then dive a little into the usage and implementation of MockWebServer. The demo project for this article is available on github.

One fine day, an android developer was feeling pretty awesome in the morning. After spending many days and nights swimming in the ocean of unlimited classes, events and interfaces, she had finally mastered the Rxify spell, the art of using Dagger and implemented MVP on her project. Little did she know, what was the true reason behind recommendation of this architecture and all the cool stuff. It was not just distribution of responsibility but also the “thing” which she had managed to avoid almost all her career.

“Testing” — the unavoidable Beast!

Maximum test-coverage for the logic layer

It was only a week earlier when her Project Manager had asked her for the estimates in the sprint planning meeting. She had confidently estimated all the stories without knowing what was coming her way.

Finally, the time came for “The Team Meeting”. The meeting which changed her whole life! Team Lead told her that her logic layer had to have as much test coverage as possible! She sat like this for the next 15 minutes :

Developer after getting the test-coverage shock! Source

Mockito

She desperately started looking into various testing frameworks and found out the ultimate “potion” to her problems : Mockito! 😀

“Why Drink it?
Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.” — Mockito.org

She quickly went through the documentation and started on the journey of writing tests. Everything was going great! She was properly Mocking out the views and creating Stubs. While trying to master the art of “when-then”, she had already started dreaming of the MockStar title.

Testing the Happy Paths of Presenter with Mockito

We have used the cute pokemons API for demo purpose here : pokeapi.

So, she was trying to test the Presenter as shown in the gist below :

She wrote the test for the above code using Mockito. She mocked out her View and PokeDataSource. Have a look at the test for the above code :

when(pokeDataSource.getPokemonAbilityStringObservable(anyString()))
.thenReturn(Observable.just(""));

After the above when-then blah blah… we test if setApiText() is called 1 time and showErrorDialog() is called 0 times. Kindly note that, what actual data is shown, it’s not tested here as it’s not the responsibility of this test case for Presenter. That responsibility lies with our DataRepository.

Everything was going good, nice and smooth so far. She similarly went on to write the tests for the other cases and finally finished writing the test cases for other Presenters in her logic layer. She ran code coverage tasks and BOOM! Not Enough Code-Coverage!

Sad developer, Not Enough Test Coverage Source

Well! That’s Sad. Now she will need to write more tests. She gets back to work and starts writing tests for some error conditions now.

Testing Error cases with Mockito

Now she wanted to test the following embarrassingly ugly if-else-if mess:

Big Deal? She confidently started to test the above cases by returning the appropriate HttpException instance. Let’s see the code she wrote :


when
(pokeSource.getPokemonAbilityStringObservable(anyString()))
.thenReturn(
Observable.<Pokemon>error(
new HttpException(
Response.error(HttpURLConnection.HTTP_NOT_FOUND,
ResponseBody.create(
MediaType.parse("God Knows What?"),
"Why am I even alive?")))));

Testing error cases Source
“It was not just enough to be able to write the logic tests and use all those cool tools, we have to have maximum test coverage for the logic layer” — She cried in her head.

After a long session of cursing-the-world due to the above “incident”, she got back to work with a cup of tea and clear mind. Then suddenly! it struck her that her whole life has been a lie. She didn’t really have to “Create” an HttpException when she had Mockito . She modified her test as follows :

AWESOME! She was able to test all the error cases just like the above. Have a look at her Presenter Test here. She again got a feeling of excitement that this might be the end of all testing-madness finally. She crossed her fingers and ran the testCodeCoverage tasks.

AND! BAM! Again “Not Enough Code Coverage! OH GOD WHY

Again Not Enough Test Coverage Source

She checked the test report and found out thatPokeDataSource had 0 lines of coverage. Ohhhhh! She still had to test her DataRepository.

Testing the DataRepository

Next morning, she started testing her DataRepository which had the following public API getPokemonAbilityStringObservable() :

She again began Mocking stuff and by now she had started to almost hate the word Mock itself. She would do anything to not use the when-then-what-who-how anymore.

Now that we are testing the data source, we need to have some sort of mock data that should be provided here, to be able to test the DataRepository properly. We could continue using Mockito and write something like :

when(pokemonService.getPokemon(anyString()))
.thenReturn(getMockPokemonResponse());

Main issue with the @Mocked PokemonService is the creation of Mock Response. The method getMockPokemonResponse() is the main culprit.

It would have still been manageable if she was testing for only pokemon.getId(). In order to be able to test the functionality properly, she had to feed it all sorts of not-so-cute values of Pokemon. Have a look at the complexity of the above response here.

She knew that she had to do something better or easier at least. This brings us to the most interesting chapter of her journey towards becoming a Mock Star 😎.

MockWebServer

It has a web server which runs on localhost and can be used to mock responses while testing our applications.

After reading MockWebServer’s documentation and watching a few episodes of CasterIO videos on MockWebServer by Chiu-Ki Chan, She finally could see it clearly in her head. Her MockStar title wasn’t too far-fetched now. Let’s see what got into her and how she took the road less travelled and implemented MockWebServer to simplify the dull and monotonous task of writing tests.

Integrate MockWebServer in your app

She created a separate java module called mocks where she would store the responses statically in json format. She named the files in the format : requestMethod_requestPath.json with all the / replaced by _.

Example : GET pokemon/12 would be converted into : get_pokemon_12.json

LocalResponseDispatcher

She wrote a Dispatcher to map the requests to their json files as follows and returned a MockResponse object with response code 200 OK :)

With this and plugging-in the MockWebServer in her repository by creating a test-dependency on the mocks module: testCompile project(':mocks'), she was able to get the tests up and running. With the help of Dagger2 and it’s supercool advantage of being able to inject dependencies specific to our tests, she was able to setup MockWebServer for her unit-tests in no-time. Let’s see how she converted the earlier tests to use MockWebServer. She changed the Mockito@Mock PokemonService to @Inject PokemonService.

Testing the DataRepository using MockWebServer

She wanted to again test the following call inside DataRepository:

She just invoked pokemonService.getPokemon() within her unit-tests and MockWebServer took care of the rest with it’s MockResponse. Have a look at the BaseLogicTest.java file here for more details.

No need to create any DemoPokemonResponse just write the logic for your tests and you are good to go! After seeing the magic of MockWebServer she went all nuts!!

Developer gone crazy Source

Testing SocketTimeoutException

Now, was the time to test the dreaded SocketTimeoutException. I think we are really blessed to have Dagger2 in our lives which makes it so easy to configure tests. Just change your OkHttpClient configuration to builder.readTimeout(2, SECONDS); and see the magic of MockResponse's throttleBody() function, also explained in this video. You can find this test and others such as testing for correct Headers using RecordedRequest here. For full code sample and setup, checkout this mockstar repository on Github.

ANNNNNNND You are done!

Let’s run the testCodeCoverage now!

Just Kiddin, Not 100% but Enough Source

She finally finished her stories even before her “extended-deadline” and took that time to read some more articles on Medium *cough* facebook *cough*.

Conclusion

Any ordinary android developer can become a MockStar by using all the right tools and by experience. There’s not just a single way of improving any code we write and I am not comparing Mockito with MockWebserver here, they both are extremely advantageous on their own. I think they can be used in conjunction, using the one where it’s needed. We can use Mockito wherever we do not require actual data and just want to test the conditional flow. And MockWebServer would come into picture where we need at least some data to be able to test something. Here, I have just covered how we can slightly “speed-up” the boring-but-yet-so-helpful task of writing unit tests in MVP.

#1 MockStar Source

I am just an ordinary developer myself — “a wannabe MockStar”, if you feel that there’s a better way, I would like to hear it. Also, the article is just a made up slightly related to the daily lives of developers like us. Let’s all improve and learn together. Kindly click the tiny heart button if you enjoyed this article.

Thank you for Reading :)