gpt4 book ai didi

java - 为什么 Mockito 不能在 Kotlin 中模拟具有数字类型的泛型参数类型?

转载 作者:IT老高 更新时间:2023-10-28 13:40:21 26 4
gpt4 key购买 nike

我们正在将项目迁移到 Kotlin 语言。我们决定从测试开始,但遇到了一些奇怪的行为。

这是我们的测试用例:

Service.java

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(工作正常)

@RunWith(MockitoJUnitRunner.class)
public final class JavaTest {
@Mock
private JdbcTemplate jdbcTemplate;

@InjectMocks
private Service testSubject;

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

//when
long result = testSubject.check();

//then
assertThat(result, is(1L));
}
}

KotlinTest.kt(不工作)

@RunWith(MockitoJUnitRunner::class)
class KotlinTest {
@Mock
private lateinit var jdbcTemplate: JdbcTemplate

@InjectMocks
private lateinit var testSubject: Service

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

//when
val result = testSubject.check()

//then
assertThat(result, `is`(1L))
}
}

Kotlin 测试失败并出现 NullPointerException:

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

此外,MockitoHint 说:

[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)

有人能描述一下这里发生了什么吗?我对 Kotlin 很陌生,可能会错过一些东西。

依赖版本:Kotlin 1.1.3-2、Mockito 2.7.19

最佳答案

请使用 KClass#javaObjectType相反,例如:

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

Why does this error occurs?

这是因为 Long::class.java返回原始类型 long类而不是 java.lang.Long类(class)。例如:

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

模拟方法参数匹配器是[String, Class< long >]在 Kotlin 测试代码中。当mockito 找不到匹配的 方法时[String, Class< Long >]用于 Java 中的 模拟 Service类,那么它将为 mismatched 返回一个 默认值 getForObject方法调用,但返回类型为 getForObject方法是Object - 所以默认返回一个 null 值。

但是,check 的返回类型方法是long ,然后 JVM 尝试 拆箱 null在您的 Service 中放入原始类型 long类 - 导致 NullPointerException被抛出。例如:

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

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

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

testSubject.check()
// ^--- throws NullPointerException

如果您将替换 Long 的用法long.class 的类(class)- 你也会得到同样的错误。例如:

//      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
fail();
} catch (NullPointerException expected) {
assertTrue(true);
}

关于java - 为什么 Mockito 不能在 Kotlin 中模拟具有数字类型的泛型参数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45172596/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com