Beginner’s Kotlin Practice: A Sample Project & Unit Tests (Java vs. Kotlin)

Nil Seri
6 min readDec 20, 2021

A Starter Project to Practice Kotlin for Java Developers

Photo by Nathan Dumlao on Unsplash

If you would like to have a look at my previous post in which I shared my study notes for Kotlin:

I had a previously implemented project in Java 16 and I decided to code a Kotlin version of it.

I implemented a TDD driven programming kata called Mars Rover with Spring Boot library (although it is just a regular command line program) and also included unit tests.

Here, I will share some of the problems I came across and how I fixed them and give you GitHub links of each project.

Configuration

Firstly, I had an error saying “intellij the compiler bundled to Kotlin plugin is older than external compiler used for building modules” in IntelliJ and I had overcome it by updating my Kotlin Compiler config:

It would be better to check your Kotlin version and Kotlin Compiler version in IntelliJ.

Here are my current versions:

IntelliJ IDEA -> Preferences -> Languages & Frameworks -> Kotlin:

IntelliJ IDEA -> Preferences -> Build & Execution & Deployment -> Kotlin Compiler:

Implementation

Auto Translation:

IntelliJ automatically converts Java code to Kotlin if you copy and paste:

Do not fully rely on that conversion, though. But it may be a good start point if you organize your code later. Our aim here is not writing Kotlin just like Java. We have to get used to Kotlin’s conventions in coding.

Serialization Import:

I had serialVersionUID in my custom Exception class and I wanted to add in Kotlin, too. I got “Cannot access ‘Serializable’: it is internal in kotlin.io” error so I had to add Kotlin serialization json dependency and added “@Serializable” on top of my Exception class declaration.

<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json</artifactId>
<version>1.3.1</version>
</dependency>

Override “toString()” in Data Class:

You can just override it, you do not have to do anything special but I wanted to check, just in case.

data class Something(
val a: String,
val b: Any,
val c: String
) {
override fun toString(): String = a + b + c
}

Internal Class Declaration for Unit Tests:

I searched for unit tests written in Kotlin and what I came across is that unit test classed were declared as “internal”.

Here, it says:

Using internal visibility means that it can be accessed by other classes in the same module. This is the closest Kotlin has to Java's default 'package-private' which also makes sense for tests written in Java.

Using private is more restrictive making it so that test classes can reuse each other which can be useful some times. There really shouldn't be a use for public test classes, unless they're global test helpers which would be the exception rather than the rule.

“kotlin-test-junit” — Kotlin Unit Test Library:

I commented out “junit” and instead I used “kotlin-test-junit” since this one is specific for Kotlin:

<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>
<version>1.6.10</version>
<scope>test</scope>
</dependency>

“lateinit” Variables in Unit Tests:

If you want to initialize your variable in the setup method of a unit test, you can declare them as “lateinit”.

From Kotlin’s official docs:

Normally, properties declared as having a non-null type must be initialized in the constructor. However, it is often the case that doing so is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test.

To handle such cases, you can mark the property with the lateinit modifier.

“mockk” — Kotlin Mocking Library:

mockk is a mocking library for Kotlin. As a start point, you can read how to use InjectMock, Spy, etc. here.

MockK requires MockKAnnotations.init(…) to be called on an object declaring a variable with annotations. For Junit5, it can be replaced with @ExtendWith(MockKExtension::class).

I chose not to use JUnit version 5 since my Spring Boot version uses version 4 so I implemented with the static “init” workaround.

Runtime Error:

When I started to run my unit tests, I kept getting “Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not “opens java.lang” to unnamed module” errors.

This happens because I use PowerMock which I use to mock or test private methods. Actually, you should not be writing unit tests for private methods since as they are private, they are an implementation detail. But since I can with PowerMock, why shouldn’t I? 😊

Since I was using Java 16 in my Java project, “ — illegal-access=permit” workaround was OK for me but you should be careful since it gives me a warning as “OpenJDK 64-Bit Server VM warning: Option — illegal-access is deprecated and will be removed in a future release.” and in many sites I visited they already removed this in Java 17.

For my Kotlin version of project, even though I did the same update, I partially got rid of the errors (the ones for Whitebox.invoke) but still got the same errors for private method verify call count checks so I decided to search for another solution but the solution came within “mockk” library.

You can check usage in mockk’s offical site under “Private functions mocking / dynamic calls” title.

So I decided to keep PowerMock for Whitebox triggers and converted whole other code to use “mockk” instead. I updated “@RunWith” annotations, too.

You can check unit test my implementation here under model, service and utils folders.

Happy Coding!

--

--

Nil Seri

I would love to change the world, but they won’t give me the source code | coding 👩🏻‍💻 | coffee ☕️ | jazz 🎷 | anime 🐲 | books 📚 | drawing 🎨