Тестирование функций расширения внутри классов - PullRequest
0 голосов
/ 05 июня 2018

Если мы хотим протестировать функцию расширения для типа, мы можем создать экземпляр этого типа, вызвать функцию и проверить возвращаемое значение.Но как насчет тестирования функций расширения, определенных внутри классов?

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() в классах SubClass1 и SubClass2?Это вообще возможно?

Я знаю, что могу изменить дизайн, чтобы протестировать его.Мне пришло в голову две возможности:

  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, и наш тест прошел бы.

Итак, возможно ли тестировать функции расширения внутриклассы ?Если нет, как бы вы изменили свой дизайн, чтобы проверить их логику?

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Методы расширения хороши, и они обеспечивают красивый свободный синтаксис, подобный тому, что есть в 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
}
0 голосов
/ 05 июня 2018

Поскольку тесты должны быть написаны с точки зрения клиента, я не уверен, что это будет правильный тест.Но я нашел один способ проверить это.

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

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

    assertThat(int, `is`(1))
}
...