Unit Test: Mockito Annotations with Kotlin

Bram Yeh
Bram Yeh
Jul 21, 2017 · 2 min read

Our team converted all unit tests from Java to Kotlin. During these practices, we learned more and became familiar with Kotlin and Mockito.

Use lateinit val for @Mock, @Captor and other annotations to avoid !! or ?

In Java, Mockito provides annotation processors to generate inject mocked spied or other instances at compile time. Here is normal example,

public class Test {

@Captor
ArgumentCaptor<Foo> captor;
@Spy
Foo spyOnFoo = new Foo("argument");
@Spy
Bar spyOnBar;
@InjectMocks
ArticleManager manager;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
....
}

And when converting to Kotlin, these injected properties become read-only but Nullable type, as following

class Test {

@Captor
val captor: ArgumentCaptor<Foo>?;
@Spy
val spyOnFoo = Foo("argument");
@Spy
val spyOnBar: Bar?;
@InjectMocks
val manager: ArticleManager?;
@Before
fun init() {
MockitoAnnotations.initMocks(this);
}
....
}

This is not good… I need to use ? or !! operations when using captor, spyOnBar and manager because they are Nullable types. This is redundant because Mockito will initialize these properties after compiled.

To reduce these unnecessary ? or !!, we can adjust these properties lateinit var and change them Non-Null type

class Test {

@Captor
lateinit var captor: ArgumentCaptor<Foo>;
@Spy
val spyOnFoo = Foo("argument");
@Spy
lateinit var spyOnBar: Bar;
@InjectMocks
lateinit var manager: ArticleManager;
@Before
fun init() {
MockitoAnnotations.initMocks(this);
}
....
}

By this simple modification, we can ignore these Null Safety check and all unit tests work correctly either.


Use @JvmField for @Rule to make those properties public in Java

Sometimes we need to use PowerMockito to mock static methods or other power opeations. And we need to set PowerMockRule public with @Rule.

@Rule
public PowerMockRule rule = new PowerMockRule();

And when we use plugin to convert, it will become

@Rule
val rule = PowerMockRule()

Then, even the property was set to be public, you will get compile error, ValidationError: The @Rule 'rule' must be public. This is because Kotlin will convert this variable into private field with public getter, so it will become

@Rule
@NotNull
private final PowerMockRule rule = new PowerMockRule();

@NotNull
public final PowerMockRule getRule() {
return this.rule;
}

That’s why it conflicts JUnit Test Rule’s requirement, Rules must be public. To fix this, we just need @JvmField to tell Kotlin compiler not to generate getters/setters for this property and just expose it as a field.

@Rule 
@JvmField
val rule = PowerMockRule()

)

Bram Yeh

Written by

Bram Yeh

Lead Android & iOS Mobile Engineer at Yahoo (Verizon Media) Taiwan https://www.linkedin.com/in/hanruyeh/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade