如何在setter上调用调用? [英] How to call invoking on a setter?

查看:24
本文介绍了如何在setter上调用调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要编写一个测试用例,该测试用例要求setter引发异常。

class ClassUnderTest {

    fun regularMethod(){ require(false)}

    var currentValue: Int = 0
        set(_) {
            require(false)
        }
}

对于常规函数,我可以简单地执行以下操作:

import org.amshove.kluent.*
import org.junit.jupiter.api.*
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class Tests {

    @Test
    fun `debug throwing fun`() {
        val f = ClassUnderTest()
        invoking { f.regularMethod() } `should throw` IllegalArgumentException::class
    }

}

但对于二传手我有点困惑

    @Test
    fun `debug throwing setter`() {
        val f = ClassUnderTest()
        //1) doesn't compile: Expected a value of type Any?
        invoking { f.currentValue = 0 } `should throw` IllegalArgumentException::class

        //2) works, but why? Is this canonical?
        invoking { 0.also { f.currentValue = it } } `should throw` IllegalArgumentException::class

        //3 compiles but no exception thrown -> test fails
        invoking { { f.currentValue = 0 } } `should throw` IllegalArgumentException::class
    }

1)是我的直觉方法。显然,设置器没有返回值。为什么不行?我定义了一个被调用的函数,所以我希望它的行为与void方法相同。

2)Android Studio推荐了这一款。为什么现在这样行得通呢?这是推荐的方式吗?

3)我自己的尝试,为什么这个不起作用?

推荐答案

查看invoking需要什么作为参数:

fun invoking(function: () -> Any?): () -> Any?

它需要一个返回任何内容的函数。

您的lambda包含赋值语句。出于这样或那样的原因,编译器无法确定如果lambda的类型被推断为() -> Unit,那么它就可以被转换为() -> Any?。即:

// here the compiler can infer that the lambda is () -> Unit
val x = { f.currentValue = 0 } 
// this now works
invoking(x) `should throw` IllegalArgumentException::class
但是,如果您要求编译器尝试将{ f.currentValue = 0 }设置为() -> Any?类型,它会突然变成哑巴并且无法执行。我认为这是因为它试图在lambda中找到一个可以转换为Any?的表达式,但却找到了一条语句。我不知道这是错误还是故意的行为。

这也行得通:

invoking({ f.currentValue = 0 } as () -> Unit) `should throw` IllegalArgumentException::class

有趣的是,IntelliJ说演员阵容是不必要的,但事实并非如此。

总之,您问题中的第二种方法是可行的,因为0.also { ... }是一个表达式。

第三种方法不起作用,因为虽然{ f.currentValue = 0 }是一个表达式,但是您传递给invoking的lambda现在变成了不会抛出的东西。它变成只返回另一个lambda的东西。您可以:

invoking { run { f.currentValue = 0 } } `should throw` IllegalArgumentException::class

invoking { { f.currentValue = 0 }.invoke() } `should throw` IllegalArgumentException::class

改为。

顺便说一句,如果invoking声明如下:

fun <T> invoking(function: () -> T): () -> Any?

那么您的直观方法&就会奏效。使用() -> Any?可能有的原因。我不是作者,所以我不知道。

这篇关于如何在setter上调用调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆