Эквивалент doReturn (x) .when (y) ... в макете? - PullRequest
0 голосов
/ 15 апреля 2019

Я ищу нецензурный эквивалент doReturn (...). Когда (...). *

Я работаю над написанием некоторых модульных тестов (контрактов на тестирование), в которых задействовано много системклассы и т. д. должны перехватывать методы, которые я не контролирую, и возвращать некоторые обратные вызовы (которые в конечном итоге должен был бы вернуть метод в коде).В mockito я мог сделать что-то вроде doReturn (...). Когда (...). *

Я не смог найти подобную вещь в mockK.Похоже, что каждый {} всегда запускает блок перед ответом или возвратом.

    class Vehicle: Listener {

    fun displayCar(listener:Listener){
        OtherClass().fetchCar(listener)
    }

    override fun showCarSuccessful() {
        //do something
    }
}

    class OtherClass {
    //assume its an outside function that returns nothing but invokes a method of listener call back
    fun fetchCar(listener: Listener) {
        //... Some system level operations that I don't have control to generate mock objects but in the test I want to use the listener to call some method so that I can
        // test some contracts
        listener.showCarSuccessful()
    }
}

    class Tests {
    @Test
    fun testCarSuccess() {
        val listener: Listener = mockk(relaxed = true)
        val vehicle = Vehicle()
    //also tried with mockkClass and others
        val other: OtherClass = mockk(relaxed = true)
   every { other.fetchCar(listener) } returns {listener.showCarSuccessful()}
   vehicle.displayCar(listener)
//do some verification checks here
    }
}

    interface Listener {
    fun showCarSuccessful()
}

1 Ответ

2 голосов
/ 15 апреля 2019

Блок every{} - это ваше предложение when.Вы можете установить несколько условий для получения разных результатов.Посмотрите пример установки фиксированного returns и выполнения прогромматического answers

import io.mockk.MockKException
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

class MyClass {

    fun add(operand1: Int, operand2: Int): Int {
        TODO()
    }
}

class MockkTest {

    @Test
    fun testMocking() {

        val myClassMock = mockk<MyClass> {
            every { add(1, 2) } returns 3 // Set behaviour
            every { add(2, 2) } returns 4 // Set behaviour
            every { add(3, 4)} answers {args[0] as Int * args[1] as Int} // Programmatic behaviour
        }

        Assertions.assertEquals(3, myClassMock.add(1, 2))
        Assertions.assertEquals(4, myClassMock.add(2, 2))
        Assertions.assertEquals(12, myClassMock.add(3, 4))

        Assertions.assertThrows(MockKException::class.java) {
            myClassMock.add(5, 6) // This behaviour has not been set up.
        }
    }
}

Но, в частности, в вашем примере я нахожу эту строку:

every { other.fetchCar(listener) } returns listener.showCarSuccessful()

очень странно.Во-первых, он не делает то, что, как вы думаете, он делает - он будет выполнять этот вызов, когда вы настраиваете это поведение, вы говорите своему макету возвращать результат этого вызова, а не выполнять этот вызов.Чтобы сделать то, что вы хотите, вы должны сделать это:

every { other.fetchCar(listener) } answers {listener.showCarSuccessful()}

Но даже тогда эта строка настраивает фиктивное поведение после того, как вы вызвали тестируемый класс - сначала настройте ваше фиктивное поведение,

Также странно, что вы настраиваете побочные эффекты в макете верхнего уровня во вложенном макете.Конечно, для тестирования вашего класса Vehicle все, что вы хотите сделать, это убедиться, что его внутренний класс был вызван с правильными аргументами.Кроме того, как Vehicle получает ссылку на ваш OtherClass макет, это создание нового экземпляра и вызов этой функции.

Вот попытка заставить ваш пример работать:

import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Test

interface Listener {
    fun showCarSuccessful()
}

class Vehicle(val other: OtherClass) : Listener {

    fun displayCar(listener: Listener) {
        other.fetchCar(listener)
    }

    override fun showCarSuccessful() {
        //do something
    }
}


class OtherClass {
    //assume its an outside function that returns nothing but invokes a method of listener call back
    fun fetchCar(listener: Listener) {

    }

}

class VehicleTest{

    @Test
    fun testDisplayCar(){
        val listener: Listener = mockk(relaxed = true)
        val other: OtherClass = mockk(relaxed = true) //also tried with mockkClass and others
        val vehicle = Vehicle(other)

        vehicle.displayCar(listener)

        verify{ other.fetchCar(listener) }
    }
}

Даже это, я думаю, все еще немного не так - я подозреваю, что слушатель, которого вы хотите Vehicle передать OtherClass, сам по себе, а не аргумент ...

Вам также следует написатьотдельный тест для OtherClass, чтобы убедиться, что он делает то, что вы ожидаете, когда вы звоните fetchCar

...