For Example I have a retrofit interface such as:
interface SampleService {
fun getSomething(@body someBody: SomeBody)
}
Now I have a class which uses this interface such as:
class UserRequester(val service: SampleService) {
fun doGetSomething(someValue: String) {
val response = service.getSomething(SomeBody(someValue))
// ...
}
}
I want to test this class but dont know how to mock it.
I'm trying the following:
val mockSampleService = mock()
val userRequester = UserRequester(mockSampleService)
val requestBody = SomeBody(someString))
when(mockSampleService.getSomething(requestBody)).return(myExpectedValue)
....
My problem is that since I create the request object inside the function, I could not make the mock when().thenReturn() to work since i am technically passing two different object.
How should I test this? Thanks in advance.
The mocking problem (UserRequester)
You are not able to mock the mockSampleService
method because your class is creating the SomeBody
object and is different from the SomeBody
object you are creating in your test.
Now you have 2 options:
Mockito.any()
in your test, in this way you basically say that whatever your method is gonna use as parameter you will return the mocked behavioursomeString
returns you a SomeObject
like this:
// 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
}
}
The second approach is the cleanest one.
Testing Retrofit calls (SampleService)
I wouldn't unit test
a Retrofit call.
When you are dealing with frameworks, apis, databases, shared preferences is always preferable to do integration tests
instead of unit tests
.
In this way you are actually testing that your code is working with the outside world.
I suggest you to test Retrofit calls with MockWebServer (it's a library from Square
, the same company that developed OkHttp and Retrofit).
This read may be also helpful.
Probably SomeBody
is a plain value object, since Retrofit requests work with value objects. If you define the equals
method for the SomeBody
class then the eq
matcher will work, and you can write using mockito-kotlin:
whenever(mockService.getSomething(eq(SomeBody(someString)))).thenReturn(stubbedResult)
Actually, you can omit the eq
matcher, Mockito will use the equals
method for matching.
If SomeBody
is a Kotlin data class
then the equals
method is automatically defined by comparing the fields.
If for some reason you don't want to rely on equals
, then you can use the argThat
matcher defined in mockito-kotlin:
whenever(mockService.getSomething(argThat { theField == someValue })).thenReturn(stubbedResult)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With