{{announcement.body}}
{{announcement.title}}

Kotlin Clean Code for Android,  Part 1

DZone 's Guide to

Kotlin Clean Code for Android,  Part 1

We go over how to get started with Kotlin Clean Code for Android and how it makes unit testing your Android apps so much easier.

Free Resource

Test Driven Development in Android Using Kotlin

This post is about my journey of finding the right mobile app unit testing framework and how I arrived at Kotlin Clean Code for Android. A design pattern, it is an adaptation of Android Clean Code. When you finish this blog series, I promise, you will learn how to unit test your mobile app, piece by piece.

Let Us Start With Unit Testing

Writing an Android app that has good unit test code coverage is not easy, as Android code typically has a massive activity or fragment class that manages more than one function or task. Typical fragment classes do the below tasks:

  • Data retrieval from data sources like APIs, the local database, or the content provider.
  • Data manipulation and decoration of the retrieved data according to UI needs.
  • UI specific activities like rendering, painting, responding to user events, and the creation of fragments.

When you try to accomplish more than one tasks in a single class, often the Activity or Fragment grows to be a massive class and its methods are intertwined and do everything, everywhere. Testing the methods in this setup is not easy, you need to have too many dependencies that need to be mocked. Maintaining the test code with many mocks takes a lot of effort. When looking at unit testing tools like JUnit, Robolectric, and Android instrumentation, we often overlook app development architecture adaptability for unit testing.

One of the major reasons behind the failure of unit test automation is an architecture of the app that does not support unit testing.

It is important to have a development architecture that supports testing and uses minimal mocking or no mocking at all. When your app development architecture does not support the unit testing inherently, the testing framework cannot lift you from the soup you have created for yourself.

Knowing that we need a good design pattern that aids testing, and using Uncle Bob’s clean-architecture as the reference guide, I have started searching for the design patterns suitable for test-driven development in mobile apps.

Uncle Bob’s Clean Code Architecture

Native Mobile Development Patterns

Out of numerous design patterns that are created for mobile app development, that one that closely resembles clean code architecture and is popular in the iOS world is VIPER.

Plain vanilla implementation of VIPER in iOS has its own challenges. There is no configurator in Uncle Bob’s Clean Architecture or VIPER (which does all the setup in the app delegate), and it results in code littered with extraneous setup code. clean-swift is an iOS pattern that overcomes these challenges, where the wiring of the dependencies was extracted to the configurator.

If the words VIPER and configurator sound new to you, don’t worry, continue reading, you will understand it later.

Wait a minute, we are discussing Android design patterns and the suggestion is to use an iOS design pattern?

Why not?

Android and iOS development are very similar, and with the clean-swift design pattern, we will be able to test at least 80% of the code.

Force fitting VIPER into Android has its sets of problems, you can read more about it on the Lyubomir blog. In Android Clean Code, which is adapted from clean-swift, the issues mentioned in the Lyubomir blog were taken care of.

Kotlin CleanCode for Android

Welcome to this world, Kotlin CleanCode For Android, build from clean-swift. It is built on the principle of SOLID programming.

This pattern is an improvised version of the Android Clean Code that was created for Java. Want to see how it works for Java — check here

Image title

Kotlin CleanCode4Android is built by splitting the monolithic activity into several units.

Image title

A) Every fragment or activity needs to get the data from one or more data source, data retrieval work will be handled by an interactor class.

B) Once the data is retrieved by the interactor, the data may need to be modified in the form that can be presented by the fragment, the class which does this work is the presenter.

C) Fragment does the regular work of presenting the data and accepting the user actions in form of events.

How do the fragment, interactor, and presenter talk to each other?

Classes talking to each other using interfaces

Using the interfaces.

When the screen needs to be loaded, it calls Interactor using the InteractorInput interface to fetch the data.

Once data retrieval succeeds or fails, Interactor calls Presenter using the PresentorInput interface to decorate the raw data.

Once the data is in a presentable form, Presenter calls Fragment using the FragmentInput interface to present the data. As you see the data flow is unidirectional.

Why use interfaces?

Classes talks to each other using these interfaces, thus, during the unit testing, we will be able to mock the other classes without much of a sweat.

Let’s Get Started

Clone the example project and open it in Android Studio.

Fragment

When designing the fragment class, we must be clear what the fragment class should do and what it should not.

Keeping the SRP principle, the work of the fragment is to present the data to the user and listen to the user actions, nothing more, nothing less.

For the fragment to present the data, it needs data from data sources. Should it get the data by itself? No, it should delegate the work to Interactor by using the interfaces. Let us define the interface:

interface HomeInteractorInput {
    fun fetchHomeData(request: HomeRequest)
}

We define a member in the Fragment class that will hold the implementation instance of the interface. The onCreate method of the Fragment should call the method that will retrieve the data for activity.

class HomeFragment : Fragment(), HomeFragmentInput {
    lateinit var output: HomeInteractorInput

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        val view =  inflater.inflate(R.layout.fragment_home, container, false)
        HomeConfigurator.configureFragment(this)
        fetchData()
        return view
    }

    fun fetchData() {
        // create Request and set the needed input
        val homeRequest = HomeRequest()
        homeRequest.isFutureTrips = true
        // Call the output to fetch the data
        output.fetchHomeData(homeRequest)
    }
}

Wait a minute, how will the output member be initialized with the proper implementation?

Configurator does the wiring of the dependencies; more on that later.

Worried about writing too much boilerplate code? If you use the KotlinCleanCode4Android scaffolding tool, these classes will be autogenerated for you.

Let us focus on the testing and write a test case to test the Fragment; you can refer to the code here. We will use Robolectric instead of JUnit to test the fragment, as Robolectric does the heavy lifting of mocking the Android ecosystem like context, android logs, etc.

We will write a simple test case to see if the Fragment is created. I call this a Canary test, to see if the basic pieces were wired properly.

@Test
    fun fragment_ShouldNOT_be_Null() {
        // Given
        val fragment = HomeFragment()
        // When

        // Then
        Assert.assertNotNull(fragment)
    }

Now that we know the fragment is indeed created, let us check if the Interactor method is called and see how we can test the fragment without Interactor.

You should be able to test without actually using Interactor. Let us use a spy to check if the method is called.

Want to understand the ideas behind spies, mocks, and stubs, check here.

Let us create the spy for the interface HomeInteractorInput.

class HomeFragmentOutputSpy : HomeInteractorInput {

        var fetchHomeDataIsCalled = false
        lateinit var homeRequestCopy: HomeRequest

        override fun fetchHomeData(request: HomeRequest) {
            fetchHomeDataIsCalled = true
            homeRequestCopy = request
        }
}

The code is self-explanatory, it implements the interface and needed methods of the interface. Also, as a spy, it records the input and sets the member to record the method it has called.

Let us create the test method to test that Interactor is called.

@Test
    fun onCreateView_shouldCall_fetchHomeData() {
        // Given
        val fragmentOutputSpy = HomeFragmentOutputSpy()

        // It must have called the onCreateView earlier,
        // we are injecting the mock and calling the fetchData to test our condition
        val homeFragment = HomeFragment()
        homeFragment.output = fragmentOutputSpy

        // When
        homeFragment.fetchData()

        // Then
        Assert.assertTrue(fragmentOutputSpy.fetchHomeDataIsCalled)
    }

Let us also test if the interactor method is called and has been given the right input.

@Test
    fun onCreateView_Calls_fetchHomeMetaData_withCorrectData() {
        // Given
        val fragmentOutputSpy = HomeFragmentOutputSpy()
        val homeFragment = HomeFragment()
        homeFragment.output = fragmentOutputSpy

        // When
        homeFragment.fetchData()

        // Then
        Assert.assertNotNull(homeFragment)
        Assert.assertTrue(fragmentOutputSpy.homeRequestCopy.isFutureTrips)
    }

Though we are unit testing a class that has simple logic, you may understand how powerful this design pattern is, which enables the developer to test whether the method is called and see the values of the parameters that are passed. In fact, the developer can unit test the fragment class, piece by piece.

Before we close this exercise, run the test cases with code coverage (Android Studio → Menu →Run →Run with coverage) and see for yourself how much of the Fragment class is covered.

In the next post, we'll cover Interactor. 

Acknowledgments

Logo by Suresh C R

Article Inspired by Clean Swift

Topics:
clean code ,mobile development ,kotlin android tutorial ,web dev ,unit testing tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}