8

如果我们想测试一个类型的扩展函数,我们可以创建一个该类型的实例,调用该函数并检查返回值。但是测试类内部定义的扩展函数呢?

abstract class AbstractClass<T> {
    fun doStuff(): T = "Hello".foo()

    abstract fun String.foo(): T
}

class SubClass1: AbstractClass<Int>() {
    override fun String.foo(): Int = 1
}

class SubClass2: AbstractClass<Boolean>() {
    override fun String.foo(): Boolean = true
}

我们如何测试foo()类中方法的逻辑SubClass1SubClass2?甚至可能吗?

我知道我可以改变设计来测试它。我想到了两种可能:

  1. 不要使用扩展功能。¯\_(ツ)_/¯

    abstract class AbstractClass<T> {
        fun doStuff(): T = foo("Hello")
    
        abstract fun foo(string: String): T
    }
    
    class SubClass1: AbstractClass<Int>() {
        override fun foo(string: String): Int = 1
    }
    

    然后我们可以创建一个对象SubClass1,调用foo()并检查返回值。

  2. 创建具有可见性的附加扩展函数internal只是为了测试逻辑。

    class SubClass1: AbstractClass<Int>() {
        override fun String.foo(): Int = internalFoo()
    }
    
    internal fun String.internalFoo(): Int = 1
    

    然后我们可以创建一个对象String,调用internalFoo()并检查返回值。但是,我不喜欢这种解决方案,因为我们可以更改的主体override fun String.foo(): Int并且我们的测试会通过。

那么,是否可以在类中测试扩展功能?如果不是,您将如何更改您的设计以测试他们的逻辑?

4

2 回答 2

12

由于应该从客户的角度编写测试,我不确定它是否是一个有效的测试。但我确实想出了一种方法来测试它。

@Test
fun `test extension function`() {
    var int = 0

    SubClass1().apply {
        int = "blah".foo()
    }

    assertThat(int, `is`(1))
}
于 2018-06-05T16:28:20.987 回答
2

扩展方法很棒,它们可以实现优美流畅的语法,就像 LINQ、Android KTX 中的那样。

但是,扩展方法不适用于子类化。这是因为扩展本质上是非面向对象的。它们类似于 Java 中可以隐藏但不能在子类中覆盖的静态方法。

如果您希望在子类中更改一些代码,请不要编写扩展方法,因为您将面临您在问题中遇到的测试障碍以及静态方法给可测试性带来的所有缺点

您的第一个示例绝对没有错,也没有充分的理由坚持在那里使用扩展方法:

abstract class AbstractClass<T> {
    fun doStuff(): T = foo("Hello")

    abstract fun foo(string: String): T
}

class SubClass1: AbstractClass<Int>() {
    override fun foo(string: String): Int = 1
}
于 2018-06-06T07:53:19.927 回答