I am trying to test this on Kotlin:
verify(myInterface).doSomething(argumentCaptor.capture())
capture.value.invoke(0L)
Where doSomething is:
doSomething((Long) -> Unit)
How can I create an ArgumentCaptor for this? Right now I am doing this
inline fun <reified T : Any> argumentCaptor() = ArgumentCaptor.forClass(T::class.java)!!
val captor = argumentCaptor<(Long) -> Unit>()
verify(mainApiInterface!!).downloadUserProfilePicture(captor.capture())
captor.value.invoke(0L)
But I am getting java.lang.IllegalStateException: captor.capture() must not be null
I also tried integrating mockito-kotlin but I get a PowerMockito error:
No instance field named "reported" could be found in the class hierarchy of org.mockito.internal.MockitoCore.
Using mockito-kotlin like this seems to work:
val myService = mock<MyInterface>()
myService.doSomething {
println(it)
}
verify(myService).doSomething(capture { function ->
function.invoke(123)
})
Edit: removed unnecessary argumentCaptor<(Long) -> Unit>().apply {} - it wasn't used
as with kotlin 1.3.72 and com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0 the following works fine for me:
create an argument captor via val captor = argumentCaptor<() -> Unit>() and call captor.capture() on it.
There's also a variant for nullable captors with nullableArgumentCaptor()
The following unit-test captures the lambda of type () -> Unit that is given to diff.open(). To capture it at runtime it then uses captor.capture()
// given
val onClose = argumentCaptor<() -> Unit>()
// when
diff.open(file, serialized) { onDiffClosed(clusterResource, documentBeforeDiff) }
// then
verify(diff).open(any(), any(), onClose.capture())
The nhaarman wrapper for mockito creates a wrapper KArgumentCaptor for the mockito class ArgumentCaptor. The nhaarman wrapper fixes your error by creating an instance instead of null as in mockito.
Related
I had an instrumented test that worked, however, then was added additional param to the object which required to call the #Composable function, so the entire test method should be marked as #Composable, so I added this annotation to the function, however, it starts to throw the error:
org.junit.runners.model.InvalidTestClassError: Invalid test class 'entpay.awl.ui.component.showpage.ScreenKtTest':
1. Method testDetails should have no parameters
So, the method looks like this
#Test
#Composable. <------ Composable annotation
fun testDetails() {
....
val window: WindowSize = rememberWindowSize() <------ This method is Composable
composeTestRule.setContent {
Details(
config = ...,
windowSize = window
)
}
}
I am a new in instrumental testing, however, I assume that I can't use #Composable methods in testing directly
How to make it work?
UPD
I also tried to put the window line in setContent, result the same
....
composeTestRule.setContent {
val window: WindowSize = rememberWindowSize()
Details(
config = ...,
windowSize = window
)
}
I am using jococo for test coverage. I want to cover every package, but I added this code
#Retention(AnnotationRetention.BINARY)
annotation class NoCoverageGenerated
to not excluded that class which I don't want to cover. But there is problem inside that class if we have any lambda function it not covering that lambda function. How can we cover lamda function ?
#NoCoverageGenerated
class ABC {
private val OnSuccessListener: (any: Any?) -> Unit = { _ ->
xyz()
}
}
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:
Use 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 behaviour
Use a factory that given a someString 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)
The problem is that there is static dependency on SomeBody's constructor:
val response = service.getSomething(SomeBody(someValue))
What you could do to have control over the instantiation of SomeBody is to use a "provider" or "factory" object, you can inject it in the constructor and invoke it at the right time:
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))
}
}
And mock it in your tests:
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)
I used an anonymous function but you might as well make it an interface.
I get to know about the Invoke operator that,
a() is equivalent to a.invoke()
Is there anything more regarding Invoke operator than please explain. Also, I did not get any example of Invoke operator overloading.
Is Invoke operator overloading possible? If possible then can anyone please explain about the Invoke operator overloading with an example? I did not get anything regarding this.
Thanks in advance.
Yes, you can overload invoke. Here's an example:
class Greeter(val greeting: String) {
operator fun invoke(target: String) = println("$greeting $target!")
}
val hello = Greeter("Hello")
hello("world") // Prints "Hello world!"
In addition to what #holi-java said, overriding invoke is useful for any class where there is a clear action, optionally taking parameters. It's also great as an extension function to Java library classes with such a method.
For example, say you have the following Java class
public class ThingParser {
public Thing parse(File file) {
// Parse the file
}
}
You can then define an extension on ThingParser from Kotlin like so:
operator fun ThingParser.invoke(file: File) = parse(file)
And use it like so
val parser = ThingParser()
val file = File("path/to/file")
val thing = parser(file) // Calls ThingParser.invoke extension function
The most way to use a invoke operator is use it as a Factory Method, for example:
// v--- call the invoke(String) operator
val data1 = Data("1")
// v--- call the invoke() operator
val default = Data()
// v-- call the constructor
val data2 = Data(2)
This is because the companion object is a special object in Kotlin. Indeed, the code Data("1") above is translated to the code as below:
val factory:Data.Companion = Data
// v-- the invoke operator is used here
val data1:Data = factory.invoke("1")
class Data(val value: Int) {
companion object {
const val DEFAULT =-1
// v--- factory method
operator fun invoke(value: String): Data = Data(value.toInt())
// v--- overloading invoke operator
operator fun invoke(): Data = Data(DEFAULT)
}
}
Operator Function invoke()
Kotlin provides an interesting function called invoke, which is an operator function. Specifying an invoke operator on a class allows it to be called on any instances of the class without a method name.
Let’s see this in action:
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting $name")
}
}
fun main(args: Array<String>) {
val greeter = Greeter(greeting = "Welcome")
greeter(name = "Kotlin")
//this calls the invoke function which takes String as a parameter
}
A few things to note about invoke() here. It:
Is an operator function.
Can take parameters.
Can be overloaded.
Is being called on the instance of a Greeter class without method name.
In addition to the other answers:
It's possible to define a class extending an anonymous function.
class SpecialFunction : () -> Unit {}
In such case, the operator invoke is already defined, so it needs to be overriden:
class MyFunction : () -> Unit {
override fun invoke() { println("Hi Mom") }
}
One more thing about syntax repercussions:
If such "functor" is called right after constructing it, you end up with double parentheses:
MyFunction()()
And, if such functor returns another functor, you may see some obscurities like
MyFunction()()()()()...
perhaps including parameters. This will not surprise anyone coming from the JavaScript world, though.
If you have some Python background,
you can think invoke in Kotlin as __call__ in Python.
By using this, you can "call" your object as if it's a function.
One difference is: you can overload invoke, but there is no official way to overload methods in Python.
I have a Kotlin class (The problem was simplified to have a basic example), in it there is a method testedMethod() I want to test interactions on.
I want to make sure the correct parameter is passed to anotherMethod(), my problem is that the parameter is not a value but a lambda function.
A simple solution in Kotlin is what I am looking for, it may or may not be based on this solution for java.
class TestedClass {
fun testedMethod() {
anotherMethod({ passedMethod() })
}
fun passedMethod() {}
fun anotherMethod(lambdaParameter: () -> Unit) {
// Does something with lambdaParameter
}
}
This is the solution I ended up using.
Basically you create a spy of the tested class to be able to verify its own method, and you use argumentCaptor to capture the passed lambda and be able to invoke what is in it.
import com.nhaarman.mockito_kotlin.argumentCaptor
import com.nhaarman.mockito_kotlin.spy
import com.nhaarman.mockito_kotlin.verify
#Test
fun lambdaParameterPassedIsCorrect() {
val testedClass = TestedClass()
val spyOfTestedClass = spy(testedClass)
val captor = argumentCaptor<() -> Unit>()
spyOfTestedClass.testedMethod()
verify(spyOfTestedClass).anotherMethod(captor.capture())
// Invoke the function passed as a parameter
// and then verify that the expected method was called
val function = captor.firstValue
function.invoke()
verify(spyOfTestedClass).passedMethod()
}
I would still be interested in a simpler solution.
You can use mockito_kotlin library, which have the function "verify".
verify(TestedClass, times(1)).anotherMethod(eq(passedMethod))
Which verify that the method "anotherMethod" of class "TestedClass" invoked once with the parameter equal to "passedMethod"