Hello everyone 🙋‍♂️ In this part I will show you some Android libraries that I used when implementing demo project. Also ,I will show you how I implemented unit testing.

Unit Testing

This is one of the reasons why clean architecture is necessary. Clean architecture makes unit testing painless and easy. I’ve implemented unit test for both libraries and the demo app.

I use Mockk library because it goes well with Kotlin. Besides it gives us nice DSL functionalities to play with.

To make unit tests easier, I’ve followed 3 rules when writing the app code:

1- Don’t make Swiss Army Knife Classes!

Every class must implement only it’s responsibilities. For example a data source must only get the data. It shouldn’t have additional computing or persistence responsibilities. So in the project a lot of classes that consist of one function. Making them a unit makes unit testing easier.(Shocking!)

2- Impl Classes are None of Your Business. Take That Interface!

When a class must be used by another class, the user class must know only what it needs. So our class must expose itself by implementing an interface. For example when repository using a data source it must only interest with the getting data. So it must just call the getData() function with the required parameters and expect the result from this call. Implementation of this DataSource interface or how it gets the data must be out of repository’s interest.

3- Just Give My Instances (In the constructor if it’s possible)

When a class must be used by another class, creation of this class must not be a part of the user class’s program logic. We have a pointy solution here: Dependency Injection. For example without DI when testing a view model’s one function that class creations must be part of this function: Interactor, Repository, DataSource and related Network Service. Additionally if it doesn’t get these instances as a parameter unit testing for this function makes no sense: Because it is not an unit anymore. Supply these dependencies via constructor is the clearest DI technique. When a class creation code is not reachable from application code, injecting a field to a class after it is created is also possible. For example an Activity can get its fields set by the DI mechanism.

Demo App Testing

core

In the core package, there is a heavy testing class for ApiCallAdapter implementation : CABDemoApiCallAdapterTest. Because there are too many possibilities when networking, all cases must be tested here.

We have only suspend fun <T : Any> adapt(serviceBody: suspend () -> Response<out BaseApiResponse<T>>?)for this class. So we must give the service body that behaves how we want, and compare the result of this function call with the expected result.

Testing Success

First, I’ve created a serviceBody mock to manipulate using spyk(It is something between mock and real object). Then I’ve made it return a response that was defined at the start of the class. Then set my conditions such as: “every response.code() function call must return 200”. After setting all conditions, the mocked serviceBody is ready. Then our adapter’s adapt function is ready to be called. I’ve used run blocking because it is a suspend function. After calling the adapter and assigning it’s result to our expected variable, we must check if the result meets expectations. In line 76, the state of result is checked. In line 79, data of success data holder is compared with our expected data.

Expected Instance

This test class goes like this. You can check all the cases that are tested at github repository.

Testing Retrofit

In order to manipulate Retrofit response I’ve used an Interceptor. Then got a response that behaves how I want:

main

In the main package I’ve tested GetUsersDataSource and UserRepositoryImpl at the data layer, MainViewMoldel at the presentation layer.

In the GetUsersDataSourceTest class, two parameters are mocked: userService and apiCallAdapter.

First apiCallAdapter is mocked and tested against desired results. Then userService is mocked and tested again. Because apiCallAdapter uses userService to get results, so manipulating userService affects apiCallAdapter’s result.

Testing the adapter
Testing the adapter with the manipulated userService

In UserRepositoryImplTest class getUserDataSource parameter is mocked. Remember that they take interfaces as constructor parameters, not implementations. This saves us from generating mock classes with their needs.

Repository test

In line 59, our data source is manipulated to return DataHolder.Success and tested in line 67. Then results are checked at line 72 and 74.

In MainViewModelTest class, guess what is mocked: Yes, it is the getUsersInteractor: Only constructor parameter of MainViewModel.

This is one of the reasons why we use view models. It is not a context dependent structure(unless it is not an AndroidViewModel). So we can unit testing without running code in a device.

MainViewModel testing

In line 45, the interactor is manipulated. Then it is executed in line 54. In the view model our functions don’t return a value. Instead they post a value to a MutableLiveData. So we must check live data’s value after execution. But live data logic is asynchronous, so we must observe the live data. Live data is observed at line 52, then verified that it’s value is changed. Finally the result is compared at line 60 with the expected result.

detail

Detail page testing has nothing special. It is tested the same way with the main package.

This is the end of demo app testing. Let’s look at library testing:

Library testing

The library mostly consists of interfaces. So there is no need for many of these classes. So there is only one test class : CABViewModelKTTest

CABViewModelKtTest

In this testing scenario, two extension functions of CABViewModel are tested. Both functions basically mock and execute the interactor, then compare results with the desired value.

Extras

In this part I want to show you some libraries/techniques that I used in demo app:

Simple Animation Popup

This a dialog library that I’ve used through the Clean App Base library. It reduces the code to show dialogs to the user.

Elements

It is a useful library to use RecyclerView in your app. I’ve used it on the main screen of the demo app.

Coil

This an image loading library for Android backed by Kotlin Coroutines.

Data Binding

This an Android feature that helps to write reactive apps. I’ve used it when loading images from the web to an ImageView and writing a Date value to a TextView in XML code.

Binding extensions
Binding usage in XML

This is how I used DataBinding in the code. In the 3rd and 15th lines binding is used with the keys that are defined in binding extensions.

That’s all for the series.

Happy coding 🎉

Part I:

--

--