Kotlin Spring Boot Unit Testing & Integration Testing with JUnit5 and Mockk ✔🚀

Debanshu Datta
Backyard Programmers
7 min readOct 2, 2021

--

Photo by Pawel Czerwinski on Unsplash

Recently I am into Spring boot application with Kotlin, it is great. If you are new to Spring boot with Kotlin, this will be helpful

Here you can find the whole source code of the project.

If you want to add Caching layer to your Springboot application you can refer to this project

I follow test-driven development as best practice; it helps to figure out bugs and prevents breaking the code in the long run. Here are some snippets and a simple project which will help in basic Unit testing and Integration testing. First always start by writing test cases then they will fail, write the required code, the test will pass, then refactor the code. Test, Code, Refactor.

I have here made a simple CRUD application that helps to manage bank details, we will write the basic writing some basic test cases with unit testing and integration testing. I can’t show you the total flow of TDD but we will focus on only writing test cases.

Let’s start by adding the required dependencies for Mockk, Junit5 is pre-added in the Springboot application. Here are the dependencies That I have added.

The most important dependencies are the last two testImplementation.

I will not explain the way API creation is you can refer here for more details. We are making Bank details storing applications.

Controller: We have two controllers here one is a PingController to check if the server is UP, second is the BankContoller which comprises the request mapping and calls the BankService and also does the exception handling.

Service: This takes the BankDataRepository interface as a constructor which injects either of the implementation MockBankDataResource and BankDataResource.

DataSource: Both MockBankDataResource and BankDataResource are implementation of BankDataRepository. With MongoDBBankRepository interface injected as a constructor parameter in BankDataResource.

Now let's get our hands dirty with testing here we will focus on only two types of testing, i.e. Unit testing and Integration Testing.

Unit Tests

UNIT TESTING is a software testing where individual units or components of a software are tested. The purpose is to validate that each unit of the software performs as designed.

If you open the test folder below the main folder, you find it will already have a test case written for you inside MongoTestingApplicationTests.kt. It may seem like an empty function with no functionality, but it has a very important thing to check where the application context is loading or not.

@SpringBootTest can be used as an alternative to the standard spring-test @ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests through SpringApplication.@Test tells JUnit they can run the public void method to which it is attached as a test case. To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method. If no exceptions are thrown, the test is assumed to have succeeded.

You can find a play button on the side if you are using Intellij, it will take some time to build and run. You will get this output, so you just ran your first test case🎊.

Testing: MockBankDataResource.kt

Now, let's write our first test case, Go to your MockBankDataResource.kt hover over the name you will find a bulb icon click on it Create Test. Select JUnit5 and click on okay.

assertThat() is from JUnit5 which help to check or assert that a particular condition is satisfied or not.

This will create a file with the name MockBankDataResourceTest.kt in the test folder. We then write the following code, as you can see it is important to dive into a declarative name like should provide a collection of banks, we divide the function into given, when, then for easier understanding with the power of Kotlin.

As you can see, we have manually created the object for MockBankDataResource, it is important to note that make easier and light functions in unit testing and avoid initializing spring context

Yes!!! you have written your first test case. So your tests are running.✨

Testing: BankServiceTest.kt

Here we are using Mockk to mock the data coming from BankDataRepository. ‘relaxed=true’ allows creation with no specific behaviour.

Integration Tests

The purpose of integration testing is to confirm that different components of the application interact with each other. Integration testing is considered complete, when actual results and expected results are same.

Now, let's start with integration testing. It is really easy, here MockMvc which will help up to start up the application and hit the endpoint with ease.

We will bisect it in steps for easier understanding,

Testing: BankController.kt

This is one of the longest test classes, don’t worry we will work through it step by step, I have added relevant snippets. I will encourage you to follow this gist simultaneously.

MockMvc is part of the Spring MVC test framework which helps in testing the controllers explicitly starting a Servlet container.

@SpringBootTest is used as an alternative to the standard spring-test @ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests through SpringApplication.@AutoConfigureMockMvc Annotation that can apply to a test class to enable and configure auto-configuration of MockMvc.@Nested is used to signal that the annotated class is a nested, non-static test class (i.e., an inner class) that can share setup and state with an instance of its enclosing class.@TestInstance is a type-level annotation that is used to configure the lifecycle of test instances(i.e. PER_METHOD, PER_CLASS) for the annotated test class or test interface.@DirtiesContext Test annotation which indicates that the ApplicationContext associated with a test is dirty and should therefore be closed and removed from the context cache.

In this, we are trying to add a new bank followed by testing to fetch the same back we are getting the same data or not. ObjectMapper is part of Jackson which helps to serialize and deserialize. Here we are using mockMvc we use simple constructor injection and pass the MockMvc. You can see below.

@SpringBootTest
@AutoConfigureMockMvc

internal class BankControllerTest @Autowired constructor(
val mockMvc: MockMvc,
val objectMapper: ObjectMapper
) {}

The above code is quite self-explanatory, first, we are making a POST request with the content, and we expect an isCreated() response and the data we just created. Then we are making a GET request with the same account number to check if the data is now present in the database.

Here we are trying to add a bank with the account number already present. This should result in an isBadRequest().

Here you can see that we put both the above function inside an inner class to organize the code. This will be beneficial when you have multiple tests to be organized.

You can get more test cases written in this gist for other cases. After you have added all the test cases run all the cases to finally check if the tests are working or not.

Now you can see that the test cases are working successfully🎊.

Kotlin makes it so easy to spring up a backend. Spring applications created using Kotlin, when compared to those created using Java, are concise and easier to maintain. Kotlin is a first-class language for programming Spring applications.

We begin with simple unit testing and finally, we wrote integration testing. Great Work!!

For any doubts and suggestions, you can reach out on my GitHub, Instagram, LinkedIn. I would be more than happy to give a helping hand.

I will well appreciate one of these 👏

--

--

Debanshu Datta
Backyard Programmers

Android(L2) @Gojek | Mobile Developer | Backend Developer (Java/Kotlin)