Тестирование модуля Kotlin для функциональных параметров и объектов

В Kotlin мы могли бы иметь функциональный объект и проходить в качестве параметра функции.

  1. Как создать единичный тест для проверки логики объекта функции? (например, funcParam ниже)
  2. Как выполнить тестирование функции с параметром функции? (например, functionWithFuncParam ниже) – т.е. могу ли я создать Mock для funcParam ?

     class MyClass1(val myObject: MyObject) { val funcParam = fun (num: Int): Int { return num * num } fun myFunctionOne() { myObject.functionWithFuncParam(funcParam) } } class MyObject () { fun functionWithFuncParam(funcParam: (Int) -> Int) { println(funcParam(32)) } } 

Предполагая, что funcParam является public вы можете проверить его как любой другой метод:

 class MyClass1Tests { val sut = MyClass1(MyObject()) @Test fun `funcParam multiplies input`() { assertThat(sut.funcParam(4), equalTo(16)) assertThat(sut.funcParam(1), equalTo(1)) assertThat(sut.funcParam(0), equalTo(0)) assertThat(sut.funcParam(-10), equalTo(100)) } } 

Если funcParam является приватным, вы не должны тестировать его поведение напрямую, а только через открытый интерфейс его класса.

При тестировании functionWithFuncParam вы можете легко обеспечить реализацию заглушки (Int) -> Int :

 class MyObjectTests { val outContent = ByteArrayOutputStream().apply { System.setOut(PrintStream(this)) } val sut = MyObject() @Test fun `functionWithFuncParam prints function output `() { sut.functionWithFuncParam { 12345678 } assertThat(outContent.toString(), containsString("12345678")) } } 

Если вы хотите протестировать взаимодействие MyClass1 с MyObject одним из способов является использование интерфейса, реализованного MyObject , в MyClass1 . Обычно лучший выбор, если 2 класса являются отдельными сотрудниками в том смысле, что они имеют отдельное, в основном, неродственное поведение:

 interface FunctionalObj { fun functionWithFuncParam(funcParam: (Int) -> Int) } class MyClass1(val myObject: FunctionalObj) { //omitted for brevity } class MyClass1Tests { var params = mutableListOf<(Int)->Int>() val sut = MyClass1(object: FunctionalObj { override fun functionWithFuncParam(funcParam: (Int) -> Int) { params.add(funcParam) } }) @Test fun `myFunctionOne calls delegate`() { sut.myFunctionOne() assertThat(params.size, equalTo(1)) assertThat(params[0], equalTo(sut.funcParam))//only if `funcParam` is public } } 

Если взаимодействие MyClass1 и MyObject более сложное (т. MyClass1 себя больше вызовов как запросов, так и команд ), это будет означать, что они сверстники работают вместе. В этом случае использование mocks может привести к хрупкому и труднопроизводственному тестированию.