Waldo sessions now support scripting! – Learn more
App Development

How to Use Mockito in Kotlin

Carlos Schults
Carlos Schults
How to Use Mockito in Kotlin
January 10, 2023
6
min read

Mockito is a mocking framework initially written for Java, but you can also use it in your Kotlin code. In fact, it's pretty easy to set up Mockito and get it running. And that's what you'll learn in this post: how to start using Mockito so you can write Kotlin unit tests that are fast and reliable.

We'll open the post by covering some mocking fundamentals. Then, we'll head to the practical portion of the post. By the end of the post, you'll be confident in using Mockito for your Kotlin code.  

Requirements

For you to follow along with the tutorial, we expect you have at least basic knowledge of Kotlin and unit testing. I'll use Maven as my dependency manager and IntelliJ IDEA as my IDE. You can, of course, use the tools you like the most.

Let's begin.

Mocking Fundamentals

Let's briefly cover some fundamentals of Mockito and mocking libraries. You can safely skip this section if you're already familiar with those concepts.

Unit testing is essential to ensure your code is of the highest quality. However, one of the most accepted definitions of unit tests says they should exercise units in complete isolation. That means that if the class under test depends on another class, you shouldn't use that other class directly but replace it with a substitute.

That's even more important if such dependency is a "gateway" to an external, nonreliable system, such as a database, an HTTP API, or the file system.

So, in these situations, you'll need a way to "trick" the code into talking to a replacement of those dependencies. That's typically an in-memory representation that returns a canned, pre-defined response.

There's a rich vocabulary around this concept, with terms such as mocks, stubs, spies, fakes, test doubles, etc., laid out in the book xUnit Test Patterns by George Meszaros. All of these concepts have subtle and not-so-subtle differences among them, as Martin Fowler explains in his article. But in practice, the industry seems to have coalesced around "mock object"—or simply "mock"—as the generic term for the concept of "a replacement of an external dependency when unit testing."

Mocking frameworks are tools capable of generating such mock objects on the fly. With a few lines of code, you can create this replacement object. You can also define how it will respond to method calls by the system under test.

Mockito is such a framework. It's a breeze to get started with, and it's easy—and, dare I say, fun—to use.

Mockito in Kotlin: Getting Started

It's finally time to roll up your sleeves and start working with Mockito. First of all, we'll need a project. We'll create a toy console app but treat it as a proxy for a much more complex project.

Creating a Toy Project

First, using your favorite IDE or editor, create a new console Kotlin project. Create a file called Book.kt and paste the following code on it:


data class Book(val title: String, val author: String, val isbn: String)

Now, add another file called BookRepository.kt:


interface BookRepository {
    fun getAll(): List<Book>
}

Add a third file (BookService.kt):


class BookService(private val repository: BookRepository) {
    fun getBooksByAuthor(authorName: String) : List<Book> {
        return repository.getAll().filter { it.author == authorName}
    }
}

As you certainly noticed, this toy app has something to do with books. It could be a system for a library or bookshop.

Installing JUnit and Writing a First Test

As a next step, let's install JUnit. Since I'm using Maven, I'll add the following to my pom.xml file:

    
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>{version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-runner</artifactId>
        <version>{version}</version>
        <scope>test</scope>
    </dependency>
    
    

Using IntelliJ IDEA, I'll go to the BookService.kt class, right-click its name, then go to Generate > Test.

I'll then select JUnit5 as the test framework, confirm BookServiceTest as the name for the class, and select the getBooksByAuthor() method for the test generation:

Mockito demo 1

This is the code the IDE generated for me:


import org.junit.jupiter.api.Test

import org.junit.jupiter.api.Assertions.*

class BookServiceTest {

    @Test
    fun getBooksByAuthor() {
    }
}

I'll add a single asset to the getBooksByAuthor() test method to check that the setup is working properly:


assertTrue(true)

After running the test (Ctrl + Shift + F10), I see that it passes indeed:

Mockito demo 2

Installing Mockito

Let's finally install the Mockito library. I'll add the following to my project's pom.xml file:

    
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>4.10.0</version>
    </dependency>
    
    

After that, I ask IntelliJ IDEA to solve the dependency by clicking on the "update dependencies" icon in the upper-right corner. And that's it.

Using Mockito for the First Time

Let's change the getBooksByAuthor() test method, replacing its contents with the following:


val mockBookRepository = Mockito.mock(BookRepository::class.java)
val bookService = BookService(mockBookRepository)
assertNotNull(bookService)

The code above is quite simple. The first line uses Mockito to create a mock object that implements the BookRepository interface. In the second line, we instantiate the BookService class, passing the mock object as an argument.

The last and final line asserts that the bookService variable isn't null. It's a placeholder assertion, and we'll replace it in the next step.

Now, let's run the test (Ctrl +Shift + F10) and, unsurprisingly, it passes.

Setting Up the Response for Our Mock Object

The test from the previous section doesn't test anything. When using mocking libraries, we usually want to set up the canned response that the mock object will give when its methods are called by the SUT (system under test).

Let's do that now.

First, just after creating the mock object, add the following lines of code:


val allBooks = listOf(
            Book("1984", "George Orwell", "12345"),
            Book("Thinking Fast And Slow", "Daniel Kahneman", "456789"),
            Book("Refactoring", "Martin Fowler", "74153"))

Mockito.`when`(mockBookRepository.getAll()).thenReturn(allBooks)

The code here is easy to understand:

  • We instantiate a list of Book objects containing three items.
  • Then, we use Mockito to instruct our mock object to return said list when its getAll() method is called.

In other words, we're setting up a canned response for the mock's method.

Next, add the following line of code:


val expected = listOf(Book("1984", "George Orwell", "12345"))

With the line above, we define the expected value we'll use later in the assertion.

The next step is performing the actual action of the test:


val sut = BookService(mockBookRepository)
val actual = sut.getBooksByAuthor("George Orwell")

Here, we instantiate the BookService, passing mockBookRepository as an argument. Notice how I'm using sut as the name for the variable. This is a convention I learned from Mark Seemann: to name the variable that represents the system under test explicitly.

The next line calls the getBooksByAuthor() method on the service, passing "George Orwell," author of the famous 1984 book, as the argument. Finally, the assertion:


assertEquals(expected, actual)

This is the complete, updated version of the test method:


@Test
fun getBooksByAuthor() {
	// arrange
	val mockBookRepository = Mockito.mock(BookRepository::class.java)
	val allBooks = listOf(
		Book("1984", "George Orwell", "12345"),
		Book("Thinking Fast And Slow", "Daniel Kahneman", "456789"),
		Book("Refactoring", "Martin Fowler", "74153"))

	Mockito.`when`(mockBookRepository.getAll()).thenReturn(allBooks)
	val expected = listOf(
		Book("1984", "George Orwell", "12345"))

	// act
	val sut = BookService(mockBookRepository)
	val actual = sut.getBooksByAuthor("George Orwell")

	// assert
	assertEquals(expected, actual)
}

Run the test, and you'll see that it passes.

Go Beyond Unit Testing!

According to Michael Feather's definition, a real unit test can't talk to the database, interact with the file system or make requests to an HTTP service. To unit test code that does those things, you must replace the calls to those dependencies with a replacement. Also, you often need to replace other classes if you want your unit test to be isolated and deterministic.

For all of the above, you need mock objects, or "fake" replacements for messy dependencies. You could create your mock objects manually, which is time-consuming and error-prone.

With a mocking framework, you can create and set up mock objects with a couple of lines of code and be ready to go.

In this post, you've seen how to start with Mockito in Kotlin, even though the tool was initially written for Java. What should your next steps be? Suggestions include reading and learning more about Mockito and exploring alternative frameworks, such as MockK.

Finally, remember that unit testing isn't the only form of automated testing, despite being a major one. There are many types of automation testing out there, meaning plenty for you to learn and tools to check out.

Since you're interested in Kotlin, chances are you could benefit from a mobile, end-to-end testing tool. Waldo is such a tool. With its scriptless test automation features, Waldo allows you to use its emulators and simulators to create functional mobile tests with ease.

Automated E2E tests for your mobile app

Waldo provides the best-in-class runtime for all your mobile testing needs.
Get true E2E testing in minutes, not months.

Reproduce, capture, and share bugs fast!

Waldo Sessions helps mobile teams reproduce bugs, while compiling detailed bug reports in real time.