One of the most complicated aspects of building robust test suites is ensuring you can mock the data your code needs and handles. There are several libraries that offer you simple and versatile solutions to this requirement, with MockK among the most popular.
MockK is, undeniably, one of the most widely adopted mocking tools for Kotlin. And in this article, we will explore how to use MockK to create a simple test in Kotlin by mocking some of the objects and methods in the project.
For the purpose of brevity, I will assume that you are already familiar with testing frameworks like JUnit and the concepts that makeup the TDD methodology. If that's not the case, I advise you to explore this article on making your first Kotlin app.
Now, let's start with some critical groundwork.
What Is Mocking?
The term "mocking" refers to the technique of programming your testing objects with expectations that specify the calls they're supposed to receive. In other words, mocking is designed to focus on the code you're trying to test rather than how external dependencies behave.
As Oleksiy Pylypenko, the creator of MockK, states: "The main point to have stubs or mocks is to isolate testing one component, which is called System Under Test, from their Dependent-On Components."
In this case, the system under test (SUT) refers to a system being tested for correct operation. At the same time, the dependent-on component (DOC) is a collaborator component that SUT requires to fulfill its duties.
MockK
MockK is a testing library that supports Kotlin language features and constructs by building proxies for mocked classes.
Given that the majority of JVM mocking libraries struggle with final classes since, in Kotlin, all classes and methods are final, the MockK approach is an excellent workaround to this limitation. Granted, you could use the open keyword in Kotlin methods and classes, but this approach usually becomes more of a hassle than what MockK offers.
Unfortunately, there's a performance hit that comes with MockK implementation on your tests, but the overall advantages of MockK over other alternatives are worth it.
Additionally, you can see how we explore other approaches to testing and debugging code in Kotlin.
Let's now walk through how to create a simple test workflow implementing MockK on a sample project.
Using MockK for Testing in Kotlin
The first step to creating the test workflow is to create a Kotlin project. I will be using Android Studio as the development platform, and a single-view sample project to illustrate the process of building the test workflow. If you have your own project and want to implement MockK on your test workflow, skip this step and follow along.
Once the sample project is up and running, go to the build.gradle file and add the following dependencies at the bottom:
Now sync the changes and let Gradle link the dependencies in your project.
You're ready to go. It's time to get into the code.
Preparing the Groundwork for MockK
Create a new file named Model.kt and add the following code:
This class will represent the data objects that the application will handle. As you can see, there's not much going on there, but that's OK. We just need it to return a string representation of its content.
Next, create a file named Repository.kt and add the following code to it:
This class represents a repository where the app retrieves data from a database or service. The object provided by this repository is our previously created model and will serve as the testing ground for the app.
Now we will need a util class to contain some helper methods that can be used to emulate some processing. Create a class called Utils.kt and add the following code:
Again, not much is happening here, just a method to generate a UUID.
Moving on, create a class named UIDataModel.kt with the following code:
If you are working with an MVVM design pattern, this class represents the ViewModel object. These classes are created to process the data retrieved from the database or service and provide the view layer with displayable data. That means these classes generally contain most of your application's logic. In our case, however, only a bare-bones structure is necessary.
Building the Functionality
Now we need to create the actual code for testing. This code exists in a class named App.kt, and the logic will be defined by an interface class called AppInterface.kt.
The code of the interface is the following:
And here's the code for the app:
The reasoning behind defining the structure of the logic with an interface is that it makes the process of testing the different aspects of the application together in one test file. This approach is particularly important if several methods pertinent to a test workflow lie on separate class files.
Building a Test With MockK
Finally, it's time to create the actual test.
Create a file in the dedicated test directory named AppTest.kt and add the following code:
As you can see, the first step is the setup of the test. Here we initialize the mock annotations so that MockK can adequately process the test class and the app instance, which will serve as our interface into the app logic we can execute.
Then, we have four different test cases where different scenarios are tested:
· That it fetches data and returns an empty result when the input is invalid
· That it throws an exception when it should
· That it retrieves valid data when the input is correct
· That it logs events properly
Remember, it's just as important to test that the app handles valid input as it does invalid input.
Finally, a teardown method guarantees that all resources are flushed and cleared for future tests. This operation is vital to ensure that subsequent tests run with the same context.
One More Thing
In order to test the log of events, you can add the following methods to the MainActivity.kt file in your project.
And that's it! All you have to do is run the test and evaluate the results.
Voilà!
You can look at the complete code and change the test cases to fit your workflow needs.
Additionally, even though I made this walk through as simple as possible, testing can sometimes be complex and tiring. But here's the thing: It doesn't have to be. I recommend you check out Waldo's extensive toolset for UI testing. It requires no coding and is very approachable, even for non-developers. You can give it a try for free.
Moving On
In the process of creating robust and reliable applications, it is inevitable that you will find yourself designing and implementing complex test scenarios and code. This is a reality of the craft for most developers working on high-profile, feature-rich, sensitive projects. And making sure that your tests are not only sound but extensive and approachable is an integral part of ensuring the quality of your product.
For us developers, it is essential that our code is not just readable but also approachable by our team. It is crucial that the technology being used is popular and has extensive documentation and use. And most importantly, our team needs to be well-versed in its complexities.
As a developer with more than 15 years of grind, I can't stress enough how important this is. And if there's anything I hope you take away from this article, it's that you need to work hard on your testing skills.
Related Readings -
Automated E2E tests for your mobile app
Get true E2E testing in minutes, not months.