Why Mockito can't mock a generic parameter type with number type in Kotlin?

We're moving our project to the Kotlin language. We decided to start from tests but faced with some strange behavior.

Here is our test case:


public final class Service {
    private final JdbcTemplate jdbcTemplate;

    public Service(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;

    public long check() {
        return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM table", Long.class);

JavaTest.java (works fine)

public final class JavaTest {
    private JdbcTemplate jdbcTemplate;

    private Service testSubject;

    public void test() {
        when(jdbcTemplate.queryForObject(anyString(), eq(Long.class))).thenReturn(1L);

        long result = testSubject.check();

        assertThat(result, is(1L));

KotlinTest.kt (not working)

class KotlinTest {
    private lateinit var jdbcTemplate: JdbcTemplate

    private lateinit var testSubject: Service

    fun test() {
        `when`(jdbcTemplate.queryForObject(anyString(), eq(Long::class.java))).thenReturn(1L)

        val result = testSubject.check()

        assertThat(result, `is`(1L))

Kotlin test fails with NullPointerException:

    at c.i.Service.check(Service.java:13)
    at c.i.KotlinTest.test(KotlinTest.kt:30)

Also, MockitoHint says:

[MockitoHint] KotlinTest.test (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:500)
[MockitoHint]  ...args ok? -> at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:500)

Can someone describe what is happening here? I'm quite new to Kotlin and might miss something.

Dependencies version: Kotlin 1.1.3-2, Mockito 2.7.19

Please use the KClass#javaObjectType instead, for example:

// use java.lang.Long rather than long ---v
when(jdbcTemplate.queryForObject(anyString(), eq(Long::class.javaObjectType)))

Why does this error occurs?

This is because Long::class.java returns a primitive type long class rather than a java.lang.Long class. For example:

println(Long::class.java.name) // long
println(Long::class.javaObjectType.name) // java.lang.Long

println(Long::class.javaObjectType == Long::class.java) 
//                                 ^--- false: their class are different

The mocked method parameters matcher is [String, Class< long >] in the Kotlin test code. When mockito can not find the matched method [String, Class< Long >] for mocking in Java Service class, then it will return a default value for the mismatched getForObject method call, but the return type of the getForObject method is Object - so a null value is returned by default.

However, the return type of the check method is long , and the JVM tries unboxing null into the primitive type long in your Service class - which causes a NullPointerException to be thrown. For example:

when(jdbcTemplate.queryForObject(anyString(), eq(Long::class.java)))

assertEquals(1, jdbcTemplate.queryForObject("<any>", Long::class.java))  
//                           ^--- matched: return 1 

assertNull(jdbcTemplate.queryForObject("<any>", Long::class.javaObjectType)) 
//                      ^--- mismatched: return null

//          ^--- throws NullPointerException

IF you will replace the usage of the Long class with long.class - you will also get the same error. For example:

//      use long.class rather than Long.class ---v
when(jdbcTemplate.queryForObject(anyString(), eq(long.class))).thenReturn(1L);

 //                      v--- matched: return 1L
assertThat(jdbcTemplate.queryForObject("<any>", long.class), is(1L));

try {
    //                        v--- mismatched: return null
    long value = jdbcTemplate.queryForObject("<any>", Long.class);
    //   ^--- throws NullPointerException when doing unboxing operation  
} catch (NullPointerException expected) {
链接地址: http://www.djcxy.com/p/96852.html

上一篇: 什么是“要求:真”包装

下一篇: 为什么Mockito无法在Kotlin中使用数字类型嘲讽通用参数类型?