153

Improve your tests with Kotlin in Android — (Pt.2) – ProAndroidDev

 6 years ago
source link: https://medium.com/@fabiocarballo/improve-your-tests-with-kotlin-in-android-pt-2-f3594e5e7bfd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Improve your tests with Kotlin in Android — (Pt.2)

Hello! This is the second part of my series on how to use Kotlin to improve your tests on Android development. In the first part, I briefly went through on what are the problems when starting testing using Kotlin and what are the options to overcome them.

1*0S2V9Vt6xRBpPkV4Y3zj9g.jpeg

This time, I will go through a simple example with the help of the Kotlin magic, as well as the essential mockito-kotlin, a Kotlin wrapper around Mockito.

Let’s start off with a simple example of a regular TemperaturePresenter class:

In the code above, we have a simple TemperaturePresenter that could be easily seen in an Android application, whose responsibility is to fetch and display the temperature in Celsius degrees kfor the current location.

However, in this class we have the particular behaviour of first trying to display a temperature to the user with the last known location, which we can get quickly, and only then try to fetch the current location (which can take some seconds) and display the corresponding temperature.

One possible test in the traditional Java-style Mockito would be this one:

So, let’s go step by step on transforming this into a more readable and light test.

Convert to Kotlin and use its quick-wins.

This is an easy one. Kotlin by definition is way less verbose than Java, and just by having to type and read less you get a better life :)

However, in this particular test you don’t get that much besides getting rid of some “;”. But we still have some work to do.

By converting to Kotlin, you gain the ability to make your test names more readable. If you notice, right now our test name is:

fun testInexactTemperatureIsDisplayedFollowedByExactTemperature()

This is just a bunch of letters all glued ones onto the others. With Kotlin you can use the backticks just to describe your test names with “regular” writing:

fun `display temperature for last known location first, and then for exact location`()

With this you can see right away what is the goal of your test and don’t need to mingle the code to understand what is going on.

Another place where we can improve our code with the power of Kotlin is in the usage of the inOrder.

We can make it mode readable and context related with the usage of the apply method. With it, you can avoid referencing to the inOrder variable every time you want to do a verification.

Mockito.inOrder(temperatureProvider, view).apply {
verify(temperatureProvider).getCelsiusTemperatureAt(lastLocation)
verify(view).displayTemperature(18f)
verify(temperatureProvider).getCelsiusTemperatureAt(currentLocation)
verify(view).displayTemperature(21f)
}

Let’s stop and take a look at our current test:

Leverage the power of mockito-kotlin

So, mockito-kotlin is a Kotlin wrapper library around the popular Java Framework Mockito: “It provides top-level functions to allow for a more idiomatic approach while using Mockito in Kotlin.”

In this test, we can use it to improve a couple of things. If you notice, we have to annotate every dependency with the `@Mock` and then in the method that runs before every test (the setUp) we would have to call a Mockito method to setup the dependencies classes that are annotated.

One way to improve it is to use mockito-kotlin to use an inline declaration of the mock, like this:

val temperatureProvider: TemperatureProvider = mock()

This code, allows you to:

  • Remove of the ‘@Mock’ annotation and the call to MockitoAnnotations.initMocks(this)
  • Remove the lateinit modifiers and make the variables final (immutability, I’m checking you out).
  • We also removed the setUp method, since that now the mocked objects variables are initialized right away, which allows us to initialize the TemperaturePresenter object with the variable declaration.

Behind the scenes, this method is just wrapping the call to the parameterized method Mockito.<T>mock(T object)

Other thing that we could do is to use the mockito-kotlin wrapper to define the mock expectations. Once again it is really simple, and we could just use:

whenever(temperatureProvider.getCelsiusTemperatureAt(lastLocation))
.thenReturn(18f)

It is a really small change, but it makes it a bit more readable (IMHO).

If for instance, you have a mocking expectation that you need to set in every test you can declare it in a idiomatic way when you declare the mock as well. So, to achieve it in our small example we would do it like this:

private val lastLocation = Coordinate(41.5, 8.9)
private val currentLocation = Coordinate(38.7, 9.7)

val locationProvider: LocationProvider = mock{
on
{ getLastKnownLocation() }.then { lastLocation }
on
{ getExactLocation() }.then { currentLocation }
}

Can you see the Kotlin magic working here? :) What really happens is that this library is leveraging the use of high-order functions.

Internally, the wrapper works out so that the on method (for our example) can be seen like this:

fun <R> on(methodCall: LocationProvider.() -> R): OnGoingStubbing<R>

You can notice the methodCall is in fact a method of LocationProvider that returns a generic type. This is the reason why we can call the getLastKnownLocation() method directly without referring to our locationProvider variable. Kotlin infers all the types and does its magic :)

To get a better idea of it the on method would break down in the following: (this can be seen in the mockito-kotlin source code):

Finally, let’s see how our Kotlin test ended up with some small changes:

This is just a small glimpse of what you can do to improve the tests by using Kotlin and mockito-kotlin. I would advise you to look up on the source code and see how the magic happens.

Thanks for reading until the end :)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK