简体   繁体   English

Mockito 的 argThat 在 Kotlin 中返回 null

[英]Mockito's argThat returning null when in Kotlin

Given the following class (written in kotlin):给定以下类(用 kotlin 编写):

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

I'm able to test in java, the test code:我可以在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;
}

The java test pass as expected, but the same test is written in kotlin: 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)
}

The kotlin version I receive the following exception: kotlin 版本我收到以下异常:

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

Why is it happening and how can I test that using kotlin?为什么会发生,如何使用 kotlin 进行测试?

I also faced the same problem.我也面临同样的问题。

And finally, I found argThat() will return null, and normally the argument in the function in kotlin, does not accept null type.最后,我发现argThat()会返回 null,并且通常 kotlin 中函数中的参数不接受 null 类型。

The source code of argThat from ArgumentMatchers.java argThat的源代码来自ArgumentMatchers.java

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

You can see that it return null .您可以看到它return null So when we mock the function, it will throw IllegalStateException, because argThat returns null and argument can't be null.所以当我们模拟这个函数时,它会抛出 IllegalStateException,因为argThat返回 null并且参数不能为 null。

It mean that if your function is:这意味着,如果您的功能是:

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

When you mock it like that:当你像这样嘲笑它时:

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

It will throw IllegalStateException它会抛出 IllegalStateException

So you should change your function like that:所以你应该像这样改变你的功能:

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

Change the "String" to "String?", make it accept null type.将“字符串”更改为“字符串?”,使其接受空类型。

My solution is to define the argument with class?我的解决方案是用类定义参数? so that it can accept null, but I don't know if it is a great solution以便它可以接受null,但我不知道这是否是一个很好的解决方案

In 2022, Mockito-Kotlin officially solves the problem. 2022 年,Mockito-Kotlin 正式解决了这个问题。

The fix is very simple: Just import the argThat<\/code> \/ eq<\/code> \/... from the mockito-kotlin<\/code> package, instead of the mockito<\/code> package, and everything is done!修复非常简单:只需从mockito-kotlin<\/code>包中导入argThat<\/code> \/ eq<\/code> \/...,而不是mockito<\/code>包,一切就完成了!

Related: https:\/\/github.com\/mockito\/mockito-kotlin\/wiki\/Mocking-and-verifying<\/a>相关: https<\/a> :\/\/github.com\/mockito\/mockito-kotlin\/wiki\/Mocking-and-verifying

"

As of this writing, mockito-kotlin hasn't been updated for more than a year.在撰写本文时,mockito-kotlin 已经一年多没有更新了。 As with all of these libraries, there's always a constant need for keeping them up-to-date, and I didn't want to get stuck with an unmaintained library.与所有这些库一样,始终需要使它们保持最新状态,而且我不想陷入未维护的库中。

So I came up with another way to solve the null issue with argThat without using any other libraries.所以我想出了另一种方法来解决argThat的空问题,而无需使用任何其他库。

Say we've an interface UuidRepository as follows:假设我们有一个接口UuidRepository如下:

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

class Entity has two properties, userId: String and uuid: String . class Entity有两个属性, userId: Stringuuid: String

The following code fails:以下代码失败:

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

with the error:有错误:

argThat { it.userId == someValue && it.uuid == "test" } must not be null argThat { it.userId == someValue && it.uuid == "test" } 不能为空

To solve this, we get all the invocation on the mock and then verify the ones we want:为了解决这个问题,我们在模拟上获取所有调用,然后验证我们想要的调用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM