Mockito的argThat在Kotlin中返回null

时间:2018-09-18 15:12:46

标签: java kotlin mockito

给出以下课程(用kotlin编写):

class Target {
     fun <R> target(filter: String, mapper: (String) -> R): R = mapper(filter)
}

我能够使用Java测试代码:

@Test
public void testInJava() {
    Target mockTarget = Mockito.mock(Target.class);
    Mockito.when(mockTarget.target(
            argThat(it -> true),
            Mockito.argThat(it -> true)
    )).thenReturn(100);
    assert mockTarget.target("Hello World", it -> 1) == 100;
}

java测试通过了预期的结果,但相同的测试用kotlin编写:

@Test
fun test() {
    val mockTarget = Mockito.mock(Target::class.java)
    Mockito.`when`(mockTarget.target(
            Mockito.argThat<String> { true },
            mapper = Mockito.argThat<Function1<String, Int>>({ true }))
    ).thenReturn(100)
    assert(mockTarget.target("Hello World") { 1 } == 100)
}

kotlin版本收到以下异常:

java.lang.IllegalStateException: Mockito.argThat<String> { true } must not be null

为什么会发生这种情况,如何使用Kotlin进行测试?

2 个答案:

答案 0 :(得分:1)

我也遇到了同样的问题。

最后,我发现argThat()将返回null,通常kotlin函数中的参数不接受null类型。

argThatArgumentMatchers.java的源代码

public static <T> T argThat(ArgumentMatcher<T> matcher) {
    reportMatcher(matcher);
    return null;
}

您可以看到它return null。因此,当我们模拟该函数时,它将抛出IllegalStateException,因为argThat 返回null 并且参数不能为null。

这意味着您的功能是:

fun doSomething(arg1: String): Int {
    // do something
}

当你这样嘲笑时:

Mockito.`when`(
    doSomething(Mockito.argThat<String> { true })
).thenReturn(100)

它将抛出IllegalStateException

因此,您应该这样更改功能:

fun doSomething(arg1: String?): Int {
    // do something
}

将“字符串”更改为“字符串?”,使其接受空类型。

我的解决方案是用类定义参数?以便它可以接受null,但我不知道这是否是一个很好的解决方案

答案 1 :(得分:0)

截至撰写本文时,mockito-kotlin的更新时间已超过一年。与所有这些库一样,始终需要不断更新它们,而我也不想卡在一个未维护的库中。

所以我想出了另一种方法来解决argThat中的null问题,而无需使用任何其他库。

假设我们有一个界面UuidRepository,如下所示:

interface UuidRepository {
    suspend fun Entity save(entity: Entity): Entity
}

Entity具有两个属性userId: Stringuuid: String

以下代码失败:

Mockito.verify(uuidRepository).save(argThat { it.userId == someValue && it.uuid == "test" })

出现错误:

argThat {it.userId == someValue && it.uuid ==“ test”}不能为空

要解决此问题,我们在模拟中获得所有调用,然后验证所需的调用:

val invocations = Mockito.mockingDetails(uuidRepository).invocations
    .filter { setOf("findById", "save").contains(it.method.name) }
    .map { it.method.name to it.arguments }
    .toMap()

assertThat(invocations).containsKey("save")
val first = invocations["save"]?.first()
assertThat(first).isNotNull
val entity = first as Entity
assertThat(entity.userId).isEqualTo(someValue)
assertThat(entity.uuid).isEqualTo("test")