122

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

 6 years ago
source link: https://medium.com/@fabiocarballo/improve-your-tests-with-kotlin-in-android-pt-3-104e1c9f77cc
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. 3)

Hey there! Here we are to the third part of this series (check part 1 and part 2 first if you want to). This time we will look into how we can improve our test assertions using one of two libraries: Kluent and Expekt, that help you to write assertions in a natural language as fluent english sentences.

1*YK5PLgDKciZ0J66Ilvb9wQ.png

This time, let’s take a look into a simple User class, with basic info such as name, age, friends and whether or not it can legally drink.

Now let’s take a look into a standard Kotlin test for the logic behind the fullName value:

If you notice, we are using the standard assertEquals to compare the expected value with the actual value. While this works, my opinion is that the tests should always be the most readable possible. This way, if we use any of the fluent assertion libraries, either Kluent or Expekt, we can get a test that looks more elegant.

For instance, if we start of with Kluent we can use the power of Kotlin and infix functions to achieve this assertion:

user.fullName `should equal` "Fábio Carballo"

As you can see, this approach follows the natural english speech, becoming easier to read.

Breaking down the source code.

This method has a fairly simple implementation. Let’s take a look at the source code:

infix fun Any.`should equal`(theOther: Any) = assertEquals(theOther, this)

What is happening here? A `should equal`extension function is being declared. Kotlin has this power to provide new functionality to a function without using inheritance or other decoration patterns.

So, by prefixing the should equal method on the receiver type Any (think about Object in Java), we are making it possible to call this method to any object in Kotlin.

But how can we call this method without using any parentheses or dots?Because it’s possible to use the infix notation (usually used in logical formulae and statements) with this type of methods.

This infix notation can be applied on functions where:

  • They are member functions or extension functions;
  • They have a single parameter;
  • They are marked with the infix keyword.

In fact, according to the Kotlin documentation, we indeed could get rid of the infix keyword and just declare it as an extension function:

fun Any.`should equal`(theOther: Any) = assertEquals(theOther, this)

Back to the power of Kluent and Expekt

If we were to write the same test using Expekt, it would be like this:

user.fullName.should.equal("Fábio Carballo")

As you can see, it is also more readable. However, the author opted for another style of tests which follow the dot notation (which allowed him to provide some extra behaviour, that we will still talk about in a bit).

With Expekt, you also have the option to describe the test in terms of the expectations such as:

expect(user.fullName).to.equal("Fábio Carballo")

Collection Assertions

But this is not all … Both libraries also provide collection assertions. Let’s see how we would write with regular assertions.

We have some options, but neither of them seems the right way to go honestly. Let’s see how we could do it with both libraries:

With Kluent with would be like this:

rui.friends `should contain` fabio

While with Expekt we could achieve by adding the dots and parentheses:

rui.friends.should.contain(fabio)

However, as I said above, Expekt has more power and we could be more precise on our assertions:

fabio.friends.should.have.all.elements(rui).and.have.size(1)

This is just a glimpse of what Expekt can do. Please go to their github and see more examples if you got curious.

Exception Assertions

Let’s introduce exception assertions by adding a simple drink method to our User class. The user can only drink if age is ≥ 18, if not we throw an UnderageDrinkingException.

If we use JUnit assertions one of our options would be to annotate the expected exception. (See the code below).

By using Kluent, we could get rid of the annotation processing and declare our expectation right in the test method.

Once again, we would follow the same style, applying the should throw function with the infix notation.

You could argue that having to wrap the action that triggers the exception inside a lambda is not very cool, and in fact, I agree with that. Although, I think is better than having to declare the expected exception in an annotation. But well, I think it comes to personal taste now.

Kluent also enables you to be more precise and test if the exception is thrown with a specific message:

So when it comes to assertions, Kluent is the winner (since Expekt doesn’t have any behavior to approach this).

Well, that was it for now. Stay tuned to part 4 :)

Thank you once again for all the feedback and support.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK