Как выполнить модульный тестовый вызов? - PullRequest
0 голосов
/ 10 декабря 2018

Например, у меня есть модифицированный интерфейс, такой как:

interface SampleService {
    fun getSomething(@body someBody: SomeBody)
}

Теперь у меня есть класс, который использует этот интерфейс, такой как:

class UserRequester(val service: SampleService) {
     fun doGetSomething(someValue: String) {
         val response = service.getSomething(SomeBody(someValue))
         // ...
     }
 }

Я хочу протестировать этот класс, ноЯ не знаю, как его смоделировать.

Я пытаюсь сделать следующее:

val mockSampleService = mock()
val userRequester = UserRequester(mockSampleService)
val requestBody = SomeBody(someString))
  when(mockSampleService.getSomething(requestBody)).return(myExpectedValue)
....

Моя проблема в том, что, поскольку я создаю объект запроса внутри функции, я не смог создать макет, когда() .thenReturn () для работы, поскольку я технически передаю два разных объекта.

Как мне это проверить?Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 11 декабря 2018

Проблема с имитацией (UserRequester)

Вы не можете смоделировать метод mockSampleService, поскольку ваш класс создает объект SomeBody и отличается от SomeBodyобъект, который вы создаете в своем тесте.

Теперь у вас есть 2 варианта:

  1. Используйте Mockito.any() в своем тесте, таким образом, вы в основном говорите, что любой ваш метод будет использоватьв качестве параметра вы вернете имитированное поведение
  2. Используйте фабрику, которая при someString возвращает вам SomeObject, например:

// the factory
class SomeObjectFactory{

    fun createSomeObject(someString: String): SomeObject {
        return SomeObject(someString)
    }

}

//the class
class UserRequester(
val service: SampleService, val factory: SomeObjectFactory
) {
     fun doGetSomething(someValue: String) {
         val response = service.getSomething(factory.createSomeObject(someValue))
         // ...
     }
 }

//the test
class MyTest{

    @Test
    fun myTestMethod(){
        val mockSampleService = mock()
        val factory = mock()
        val someBody = mock()
        val userRequester = UserRequester(mockSampleService, factory)
        `when`(factory.createSomeObject(someString)).thenReturn(someBody)

  `when`(mockSampleService.getSomething(someBody)).thenReturn(myExpectedValue)
    //rest of the code
    }

}

Второй подход - самый чистыйone.

Тестирование вызовов Retrofit (SampleService)

Я бы не unit test вызов Retrofit.

Когда вы работаете с фреймворками,apis, базы данных, общие предпочтения всегда предпочтительнее делать integration tests вместо unit tests.

Таким образом вы фактически проверяете, что ваш код работает с внешним миром.

Iпредлагаем вам проверить вызовы дооснащения с помощью MockWebServer (это библиотека из Square, той же компании, которая разработала OkHttp и Retrofit).

Это read также может быть полезным.

0 голосов
/ 11 декабря 2018

Вероятно, SomeBody - это объект с простым значением, поскольку запросы Retrofit работают с объектами-значениями.Если вы определите метод equals для класса SomeBody, тогда будет работать сопоставитель eq, и вы сможете писать, используя mockito-kotlin :

whenever(mockService.getSomething(eq(SomeBody(someString)))).thenReturn(stubbedResult)

На самом деле выможет опустить сопоставление eq, Mockito будет использовать метод сопоставления equals.

Если SomeBody является котлиным data class, то метод equals автоматически определяется путем сравнения полей.

Если по какой-то причине вы не хотите полагаться на equals, тогда вы можете использовать сопоставитель argThat, определенный в mockito-kotlin:

whenever(mockService.getSomething(argThat { theField == someValue })).thenReturn(stubbedResult)
0 голосов
/ 10 декабря 2018

Проблема в том, что существует статическая зависимость от конструктора SomeBody:

val response = service.getSomething(SomeBody(someValue))

Чтобы вы могли контролировать экземпляр SomeBody, вы должны использовать «провайдера» или«фабричный» объект, вы можете вставить его в конструктор и вызвать его в нужное время:

interface SampleService {
    fun getSomething(someBody: SomeBody)
}

open class SomeBody(val body: String)

open class UserRequester(
    val service: SampleService,
    val someBodyProvider: (String) -> SomeBody
) {

    fun doGetSomething(someValue: String) {
        val response = service.getSomething(someBodyProvider(someValue))
    }
}

И смоделировать это в своих тестах:

val someValue = "foo"
val sampleService: SampleService = mock()
val someBody: SomeBody = mock()
val someBodyProvider: (String) -> SomeBody = mock {
    on { invoke(someValue) }.thenReturn(someBody)
}
val userRequester = UserRequester(sampleService, someBodyProvider)

userRequester.doGetSomething("foo")

verify(sampleService).getSomething(someBody)
verify(someBodyProvider).invoke(someValue)

Я использовал анонимную функциюно вы могли бы также сделать это interface.

...