How to use Mockito in Kotlin with examples

8 min read
May 16, 2023

It’s important to ensure that the code you write is not only high-quality but also works as intended. 

Testing is a crucial component of the software development process, and developers have access to a wide range of testing frameworks and tools. 

One such popular testing framework for Kotlin is Mockito, which enables you to create mock objects that simulate dependencies and interactions with other parts of your code. 

In this blog post, we’ll dive into the world of using Mockito to create effective unit tests for Kotlin code. 

We’ll start by covering the basics of mocking and stubbing, then proceed to demonstrate how to create mock objects and utilize Mockito to verify behavior and test exceptions. 

Whether you’re new to Kotlin or an experienced developer, this post will equip you with valuable insights on how to effectively use Mockito to write better unit tests for your Kotlin code. 

So, if you’re ready to take your code testing to the next level, keep reading!

What is Mockito?

Mockito is a popular open-source testing framework for Kotlin (and Java) applications. It allows developers to create mock objects, which are simulated objects that behave like real objects but are used for testing purposes.

Mockito with Kotlin

Source: Beom Dev Log

By using mock objects, developers can isolate their code under test from external dependencies or systems, such as databases, networks, or file systems. This allows for more focused and effective testing and can lead to faster, more reliable, and more maintainable code.

Some benefits of using Mockito are:

  • Ease of use – it provides a simple and intuitive API for creating and configuring mock objects, which can help you write tests more quickly and effectively.
  • Isolation of dependencies – it allows you to isolate your code under test from its dependencies. By using mock objects to simulate the behavior of external systems or objects, you can focus your testing efforts on the code itself and verify that it behaves correctly in a controlled environment.
  • Integration with other testing frameworks – it can be used in combination with other testing frameworks, such as JUnit, to provide a comprehensive testing solution for your project.
  • Improved code quality – by writing effective tests for your Kotlin code, you can identify and fix issues earlier in the development process, leading to improved code quality and fewer bugs in production.

Mockito is a powerful testing framework that offers a wide range of methods and features for creating and using mock objects in your unit tests. 

Here are some of the most popular methods in the Mockito framework:

mock() – creates a mock object based on the class or interface you pass as an argument.

val mockCallService = mock<CallService>()
or
val mockCallService : CallService = mock()

whenever() – sets up the behavior of a mock object. It is used to specify a return value of a function, or to throw an exception when a function is called.

thenReturn() – this function is used to specify the return value of a function in a mock object.

whenever(mockCallService.isContactAvailable())
.thenReturn(true)

any() – this function is used as a placeholder for any value of a certain type, it replaces the specific value of a function argument.

whenever(mockCallService.addContact(any()))
.thenReturn(Contact(1L, “john.doe@mail.com”, “315 194 6020”))

verify() – this function is used to check that a function was called on a mock object with the correct arguments.

mockCallService.callNumber(“315 194 6020”)
verify(mockCallService).callNumber(“315 194 6020”)

doAnswer() – this function is used to define a custom behavior for a mock object, it can be used to execute custom code when a function is called on the mock object.

doAnswer { invocation ->
   val phoneNumber = (invocation.arguments[0] as? String)!!
   phoneNumber.removePrefix(SOME_PREFIX)
}.whenever(mockCallService).stripPrefixFromPhoneNumber(any())

Here we covered the most popular and the most used Mockito functions that can help you in the process of writing unit tests. If you want you can explore a lot more helper functions here.

How to use Mockito in Kotlin

Now that we’re aware of what Mockito is, let’s look at how to apply it to a Kotlin project. 

You must add the dependency listed below to the build.gradle file if you wish to use the Mockito framework in your project.

testImplementation ("org.mockito.kotlin:mockito-kotlin:$latest_version")

The Maven Central website contains the $latest_version of the Mockito framework. 

After completing the necessary setup, let’s examine a real-world situation in which a straightforward code base is tested using the Mockito framework.

First, as you can see, we have a simple data class called User that serves as a data holder of  some basic information about the user.

data class User(
   val id: Long,
   val name: String,
   val email: String
)

The UserRepository interface serves as a “bridge” to connect the data layer with the user service’s business logic.

interface UserRepository {
   fun findById(id: Long): User?
   fun save(user: User): User
   fun deleteById(id: Long)

Finally, we have a basic UserService class with our business logic.

class UserService(private val userRepository: UserRepository) {
   fun getUser(id: Long): User? {
       return userRepository.findById(id)
   }
   fun saveUser(user: User): User {
       return userRepository.save(user)
   }
   fun deleteUser(id: Long) {
       userRepository.deleteById(id)
   }
}

The first step in testing our business logic class UserService would be to create an appropriate class which will be called UserServiceTest and it will hold the test cases.

In test cases we use the real instance of the class under test, not a mocked one. But all the required classes on which our class under test depends are being mocked.

To be able to test the appropriate functionality we need to have an instance of the UserService class so we can call the desired functions and test their behavior. 

So we need to create a mock instance of the UserRepository as shown below. When the mocked object is created it can be used to create the required instance of the UserService class.

private val userRepositoryMock: UserRepository = mock()
private val userService = UserService(userRepositoryMock)

Here’s a simple diagram to explain the matter further.

image 21

Source: vogella

As you can see the getUser function is used to retrieve a User, so let’s check if it works as expected. 

We’ll start by setting up the desired behavior of our mock using the whenever function. 

As you can see we use the any function which in this place is a placeholder for a Long value type passed to the findById function. 

At the end we call the thenReturn function which returns a mocked USER. After we create the desired behavior we just need to call the getUser function from the UserService class and check that the returned User is equal to the expected value using assertEquals.

@Test
   fun `assert that the expected user is being returned`() {
       whenever(userRepositoryMock.findById(any())).thenReturn(USER)
       val user = userService.getUser(1L)
       assertEquals(USER, user)
   }

The other test case for the getUser function would be to check if it works as expected when an invalid userId is provided for example. In that case, the returned value should be null.

The mock behavior stays the same as in the previous test case. We just need to return a null value using the thenReturn function rather than a User value. 

When we call the getUser function from the UserService class we pass an invalid user id. Now we just need to check if the returned value is equal to null using assertNull.

  @Test
   fun `assert that null is returned for invalid user id`() {
       whenever(userRepositoryMock.findById(any())).thenReturn(null)
       val user = userService.getUser(-101L)
       assertNull(user)
   }

A test case for the saveUser function could be the same as the first test case which covers the getUser functionality where we check if the returned value of the User is the expected one.

Just in this case, we’d check if the saved User is the same as the returned one.

I have never seen a piece of code that couldn’t be improved by adding a few tests.

Kent Beck, software engineer

When it comes to checking if some functionality is called using the right argument, or if it is called the correct number of times we can use the verify function.

The first test case below shows how to check if a function was called using the correct provided argument, and the second test case shows how to check if a function was called the correct number of times, using the times function.

   @Test
   fun `verify deleteById was called with the correct argument`() {
       userService.deleteUser(USER_ID)
       verify(userRepositoryMock).deleteById(USER_ID)
   }
@Test
   fun `verify deleteById was called only once`() {
       userService.deleteUser(USER_ID)
       verify(userRepositoryMock, times(1)).deleteById(USER_ID)
   }

All of these examples should equip you well on your way to use Mockito with Kotlin.

Using Mockito in Kotlin: conclusion

Mockito is a powerful testing framework that can greatly simplify the process of writing tests for Kotlin and Java code. 

With Mockito you can easily create mock objects, specify custom behavior for functions and verify function calls with specific arguments.

By writing tests, you can ensure that your code behaves as expected and catch bugs before they reach production.

Here at DECODE, we’re all about testing. Every developed feature goes through several test circles which ensure high-quality code and great application performance. So feel free to check out how we do quality assurance.

Till next time, happy coding. 😊✌🏼

Categories
Written by

Domagoj Rundek

Software Engineer

Related articles