unit testing extension function and mocking the other methods of the class - kotlin

I am writing an extension function adding some retry capabilities to AmazonKinesis.putRecords. In my extension method i do some logic and some calls to the original putRecords method:
fun AmazonKinesis.putRecordsWithRetry(records: List<PutRecordsRequestEntry>, streamName: String) {
//...
val putRecordResult = this.putRecords(PutRecordsRequest().withStreamName(streamName).withRecords(records))
//...
}
From a unit test point of view I am finding it hard to see how I should mock the call to this.putRecords
I am using com.nhaarman.mockitokotlin2.*
val successfulRequest = PutRecordsResultEntry().withErrorCode(null);
class KinesisExtensionTest : StringSpec({
val testRecords = ArrayList<PutRecordsRequestEntry>()
testRecords.add(PutRecordsRequestEntry().withPartitionKey("iAmABunny").withData(ByteBuffer.wrap("aaa".toByteArray()))
)
val kinesis = mock<AmazonKinesis>{
on { putRecordsWithRetry(testRecords, "/dev/null") }.thenCallRealMethod()
on { putRecords(any()) }.thenReturn(PutRecordsResult().withRecords(listOf(successfulRequest, successfulRequest)))
}
"can write a record" {
kinesis.putRecordsWithRetry(testRecords, "/dev/null")
verify(kinesis).putRecord(any())
}
})
The putRecordResult is always null

The extension function AmazonKinesis.putRecordsWithRetry will be compiled to a static function under the hood, and Mockito doesn't support static method mocking yet.
Therefore Mockito may not know the stubbing information at the verification step and thus the default null value is produced.

Related

Is there a way to mock the invocation of a secondary constructor of a Kotlin data class using mockk

From the documentation of mockk.io regarding the mocking capabilities of constructors I can see the following:
class MockCls(private val a: Int = 0) {
constructor(x: String) : this(x.toInt())
fun add(b: Int) = a + b
}
mockkConstructor(MockCls::class)
every { constructedWith<MockCls>().add(1) } returns 2
As far as I understood it is possible to mock the construction of an object and get a result for an executed method.
What I would like to have is e.g. the following
data class MyDataClass(val first: String) {
constructor(anotherDataClass: AnotherDataClass) : this(
first = anotherDataClass.second
)
}
data class AnotherDataClass(val second: String)
mockkConstructor(MyDataClass::class)
every { constructedWith<MyDataClass>() } returns mockk<MyDataClass>
or
every { anyConstructed<MockCls>() } returns mockk<MyDataClass>
In the end, I want to bypass the construction and directly return a constructed mock and not first execute a method and return the result.
Avoiding constructor execution while mocking not currently (<=1.12.0) possible by design (https://github.com/mockk/mockk/issues/515)
If you really want to capture instance while doing constructor mocking, you can get away with this:
val myMockedInstance: MyClass = MockKGateway.implementation().constructorMockFactory.mockPlaceholder(
MyClass::class,
args = arrayOf<Matcher<*>>(
EqMatcher(dummyParamOfMine)
) as Array<Matcher<*>>
)

How to test add method in Kotlin object Singleton class

I'm trying to do some testing in my object kotlin class, but I can getting an error in my thenReturn method when I try to pass the object. I get a Require: Unit! Found checkout. Someone can point me how is possible to test it??
If I remove thenReturn method I get this error:
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
I refer this link but I can't get it.
object CheckoutRepository: CheckoutContract.Model {
var checkout: MutableList<Checkout> = mutableListOf<Checkout>()
override fun addProductToShoppingCart(checkoutProduct: Checkout){
checkout.add(checkoutProduct)
}
override fun getProductsInShoppinCart() : List<Checkout>?{
return checkout
}
override fun cleanCheckout(){
checkout.clear()
}
}
#Test
fun test_with_mock() {
val mock = mock<CheckoutContract.Model>()
var checkout = Checkout("VOUCHER", "voucher", 35.0, 5)
mock.addProductToShoppingCart(checkout)
val answer = mock.getProductsInShoppinCart()
`when`(mock.addProductToShoppingCart(checkout)).thenReturn(checkout)
assertNotNull(checkout)
assertEquals(checkout, answer)
}
In your function addProductToShoppingCart don't have any return type.
if you want check Checkout class make the change in the functions then test case will pass
override fun addProductToShoppingCart(checkoutProduct: Checkout):Checkout{
checkout.add(checkoutProduct)
return checkout
}

How to mock lambda with mockito in kotlin

I have a kotlin Android app. There is a function that loads compositions from the backend and returns them to a callback:
getCompositons(callback: (Array<Composition>) -> Unit)
How can I mock the callback using mockito. So that I then can do something like this:
var callback = //mockito mock
getCompositons(callback)
verify(callback, timeout(10000)).apply()
I read that lambda are matched to the java type function and therefore I assume apply could be the method invoked. Maybe I could mock a function and use that? But the Kotlin function interface only seems to have one return type, no parameters. java.util.Function says unresolved reference function.
Any help appreciated.
This is really no different to mocking any other type:
val callback = mock<(Array<Composition>) -> Unit>()
getCompositons(callback)
verify(callback)(any()) // Or verify(callback).invoke(any()) to be explicit
(In case you weren't aware of them, I'm using the mockito-kotlin bindings here.)
You can do that like this:
val function: Array<Composition>) -> Unit = {}
val callback = mock(function::class.java)
getCompositons(callback)
verify(callback)(any()) // or for example verifyNoInteractions(callback)
No extra libraries besides the standard mockito are needed
I solved here mocking the callback like this:
private val onNewUrl: (url: String) -> Boolean = mock {
on { mock(any()) } doReturn true
}
verify(onNewUrl).invoke(any())

How to mock a private function in android test with MockK?

I can't seem to mock private functions in android tests. I'm also using the all-open plugin for pre-P testing. On non-android tests it runs with no problems. I figured it should work on android too, because it's marked on MockK-android. Is this not implemented or am I missing something obvious?
androidTestImplementation "io.mockk:mockk-android:1.8.7"
#OpenForTesting
class A {
fun publicFun() = privateFun()
private fun privateFun() {}
protected fun protectedFun() {}
}
#Test
fun privateFunctionMock() {
val spy = spyk<A>()
val mock = mockk<A>()
val a = A()
val functions = a::class.functions // size -> 6
val spyFunctions = spy::class.functions // size -> 5
val mockFunctions = mock::class.functions // size -> 5
every { spy["privateFun"]() } returns Unit
a.publicFun()
}
Fails with Exception, because the private function is missing.
io.mockk.MockKException: can't find function privateFun() for dynamic call
Subclassing is employed to create mocks and spies for pre-P android instrumented tests. That means basically private methods are skipped because it is not possible to inherit them. That way counters are not counting private methods.
InternalPlatformDsl.dynamicSet(autoBannerViewPagerMock, "mBannerList", list)
every { autoBannerViewPagerMock.invoke("loadCoverImage") withArguments listOf(any<Int>(), any<Int>(), any<ImageView>(), any<stMetaBanner>()) } returns Unit

How to correct "verify should appear after all code under test has been exercised" when verify is last?

I get the error "verify should appear after all code under test has been exercised" with the following:
class CowTest extends MockFactory {
Cow.init(testCowProcesses)
#Test
def noProcessesTest: Unit = {
val cow: Cow = Cow(testCowProcesses)
cow.simulateOneDay(0 nanoseconds)
}
#Test
def processSimulationTest: Unit = {
val NUMBER_OF_TRIES: Int = 10
val cow: Cow = Cow(testCowProcesses)
for (ii <- 0 until NUMBER_OF_TRIES) {
cow.simulateOneDay(0 nanoseconds)
}
(cow.metabolicProcess.simulateOneDay _).verify(0 nanoseconds).repeated(NUMBER_OF_TRIES)
}
}
testCowProcesses is defined in another file, like this (abbreviated):
object CowTesters extends MockFactory {
val metProc = stub[MetabolicProcess]
(metProc.replicate _).when().returns(metProc)
val testCowProcesses = CowProcesses(metProc)
}
I don't quite understand the error message. If I comment out the verify line, the test runs. Alternatively, if I comment out the first test, the second test can run. There are no other tests in the test class. This seems to indicate that the stub objects cannot be reused, as they were in mockito (I'm adapting code from mockito).
Is the best solution to reinstantiate the mock objects, perhaps by converting CowTesters into a class?
Edit:
I confirmed the above suggestion works (not sure if it is the best), but in the mean time I did something a bit more convoluted to get me through compiles:
//TODO: once all tests are converted to ScalaMock,
//TODO: just make this a class with a companion object
trait CowTesters extends MockFactory {
val metProc = stub[MetabolicProcess]
(metProc.replicate _).when().returns(metProc)
val testCowProcesses = CowProcesses(metProc)
}
object CowTesters extends CowTesters {
def apply(): CowTesters = new CowTesters {}
}
From your code above, it seems you are either trying to use JUnit or TestNG. ScalaMock doesn't support either of those frameworks directly, which is why you are struggling with the verification of mocks.
You need to implement your tests using either ScalaTest, or Specs2. See http://scalamock.org/user-guide/integration/
The conversion from JUnit to ScalaTest should be pretty straightforward if you switch to e.g. a FunSuite: http://www.scalatest.org/user_guide/selecting_a_style