nin*_*nja 8 java junit unit-testing mockito kotlin
我们正在将项目转移到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);
}
}
Run Code Online (Sandbox Code Playgroud)
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));
}
}
Run Code Online (Sandbox Code Playgroud)
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))
}
}
Run Code Online (Sandbox Code Playgroud)
Kotlin测试因NullPointerException而失败:
java.lang.NullPointerException
at c.i.Service.check(Service.java:13)
at c.i.KotlinTest.test(KotlinTest.kt:30)
Run Code Online (Sandbox Code Playgroud)
另外,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)
Run Code Online (Sandbox Code Playgroud)
有人可以描述这里发生了什么吗?我对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)
Run Code Online (Sandbox Code Playgroud)
为什么会出现此错误?
这是因为Long::class.java返回原始类型long类而不是java.lang.Long类.例如:
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
Run Code Online (Sandbox Code Playgroud)
的嘲笑方法参数匹配是在科特林测试代码.如果可以的Mockito找不到匹配的方法进行嘲讽中的Java 类,那么它将返回默认值的匹配方法调用,但返回类型的方法是-这么一个空值默认返回.[String, Class<long>][String, Class<Long>]Service getForObjectgetForObjectObject
然而,返回类型check的方法是long,和JVM试图拆箱 null到原始类型长在你的Service类-这会导致一个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
Run Code Online (Sandbox Code Playgroud)
如果您将Long用long.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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2776 次 |
| 最近记录: |