Equivalent of doReturn(x).when(y)... in mockk? - kotlin

I am looking for a mockk equivalent of doReturn(...).when(...).*
I am working on writing some unit tests (testing contracts) that involves a lot of system classes and so need to intercept the methods that I don't control and return some call backs (which the method in code would have eventually returned). In mockito, I could do something like doReturn(...).when(...).*
I Wasn't able to find a similar thing in mockK. Seems like every{} always runs the block before answers or returns.
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()
}

The every{} block is your when clause. You can set up multiple conditions for returning different results. See the example of setting up fixed returns and performing progrommatic 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.
}
}
}
But, in your example in particular, I find this line:
every { other.fetchCar(listener) } returns listener.showCarSuccessful()
very strange. First it is not doing what you think it is doing - it is going to make that call as you set this behaviour up you are telling your mock to return the result of that call, not to do that cal. To do what you want to do, you should rather do this:
every { other.fetchCar(listener) } answers {listener.showCarSuccessful()}
But even then, this line is setting up the mock behaviour after you have called your class under test - set up your mock behaviour first.
Also, it is strange that you are setting up side effects in a top level mock in a nested mock. Surely for testing your Vehicle class all you want to do is verify that its inner class was called with the correct arguments. Also, how does Vehicle get a reference to your OtherClass mock, it is instantiating a new one and calling that function.
Here is an attempt to make your example work:
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) }
}
}
Even this I think is maybe still a bit off - I suspect that the listener you want Vehicle to pass to OtherClass is itself, not an argument...
You should also then write a separate test for OtherClass to make sure it does what you expect it to when you call fetchCar

Related

How can Mockito mock a Kotlin `use` (aka try-with-resource)?

If I were trying to add mocks to the following code (where the MyTypeBuilder is mocked to return a mocked MyType - which implements Closeable):
myTypeBuilder.build(myTypeConfiguration).use { myType ->
myType.callMyMethod()
}
Then trying to verify interactions with myType.callMethod() something like:
myType: MyType = mock()
myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
doMethodCall()
verify(myType, times(1)).callMyMethod()
I'm getting errors:
Wanted but not invoked:
myType.callMethod()
-> at package.me.MyType.callMyMethod(MyType.kt:123)
However, there was exactly 1 interaction with this mock:
myType.close()
-> at kotlin.io.CloseableKt.closeFinally(Closeable.kt:57)
So it appears that I need to add a whenever to execute the use block, but I'm not sure what that should look like. Alternatively, the use should act like a Mockito spy rather than a mock, but then allow mocking on the other methods.
I tried to reconstruct the error by writing the following code which is basically what you wrote in your question plus some println statements and some boilerplate to make it runnable:
import org.junit.jupiter.api.Test
import org.mockito.Mockito.*
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.Closeable
open class MyTypeBuilder {
open fun build(config: Any): MyType {
println("build")
return MyType()
}
}
open class MyType : Closeable {
fun callMyMethod() {
println("callMyMethod")
}
override fun close() {
println("close")
}
}
val myTypeConfiguration: Any = "heyho"
fun call(myTypeBuilder: MyTypeBuilder) {
myTypeBuilder.build(myTypeConfiguration).use { myType ->
println("call")
myType.callMyMethod()
}
}
class MockAndUseTest {
#Test
fun test() {
val myType: MyType = mock()
val myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
call(myTypeBuilder)
verify(myType, times(1)).callMyMethod()
}
}
When I run the test case test, it succeeds and is green.
So, unfortunately whatever may cause your problem, it is not contained in the details given by your question.

Allow function calls only in special context

I'm trying to write a class that only allows certain methods to be called in a lambda of one function.
Basically, I want to achieve similar behaviour to how you can only call suspend functions in a suspend context.
Right now the closest I can get is this.
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(commandContext)
// do cleanup work
}
val commandContext = CommandContext()
inner class CommandContext {
fun commandFunc() {} // only callable from the lambda
}
}
The issues I'm having with this is I can't make CommandContext private so you could always make your own instance and run the command externally. It is also unnecessary for it to be instantiatable but I can't make an "inner object."
Any ideas on how to do this cleaner?
Outer scope should know that there is a commandFunc() method in CommandContext class (and that this class actually exists). That's why it can't be private. But you can encapsulate its implementation, effectively making it private, keeping public only its interface:
interface CommandContext {
fun commandFunc()
}
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(CommandContextImpl)
// do cleanup work
}
private object CommandContextImpl : CommandContext {
override fun commandFunc() {} //actual implementation
}
}
//Usage:
fun main() {
MyClass().runCommands { commandFunc() }
}

Access ApplicationCall in object without propagation

Is there a thread-safe method in Ktor where it is possible to statically access the current ApplicationCall? I am trying to get the following simple example to work;
object Main {
fun start() {
val server = embeddedServer(Jetty, 8081) {
intercept(ApplicationCallPipeline.Call) {
// START: this will be more dynamic in the future, we don't want to pass ApplicationCall
Addon.processRequest()
// END: this will be more dynamic in the future, we don't want to pass ApplicationCall
call.respondText(output, ContentType.Text.Html, HttpStatusCode.OK)
return#intercept finish()
}
}
server.start(wait = true)
}
}
fun main(args: Array<String>) {
Main.start();
}
object Addon {
fun processRequest() {
val call = RequestUtils.getCurrentApplicationCall()
// processing of call.request.queryParameters
// ...
}
}
object RequestUtils {
fun getCurrentApplicationCall(): ApplicationCall {
// Here is where I am getting lost..
return null
}
}
I would like to be able to get the ApplicationCall for the current context to be available statically from the RequestUtils so that I can access information about the request anywhere. This of course needs to scale to be able to handle multiple requests at the same time.
I have done some experiments with dependency inject and ThreadLocal, but to no success.
Well, the application call is passed to a coroutine, so it's really dangerous to try and get it "statically", because all requests are treated in a concurrent context.
Kotlin official documentation talks about Thread-local in the context of coroutine executions. It uses the concept of CoroutineContext to restore Thread-Local values in specific/custom coroutine context.
However, if you are able to design a fully asynchronous API, you will be able to bypass thread-locals by directly creating a custom CoroutineContext, embedding the request call.
EDIT: I've updated my example code to test 2 flavors:
async endpoint: Solution fully based on Coroutine contexts and suspend functions
blocking endpoint: Uses a thread-local to store application call, as referred in kotlin doc.
import io.ktor.server.engine.embeddedServer
import io.ktor.server.jetty.Jetty
import io.ktor.application.*
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import kotlinx.coroutines.asContextElement
import kotlinx.coroutines.launch
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
/**
* Thread local in which you'll inject application call.
*/
private val localCall : ThreadLocal<ApplicationCall> = ThreadLocal();
object Main {
fun start() {
val server = embeddedServer(Jetty, 8081) {
routing {
// Solution requiring full coroutine/ supendable execution.
get("/async") {
// Ktor will launch this block of code in a coroutine, so you can create a subroutine with
// an overloaded context providing needed information.
launch(coroutineContext + ApplicationCallContext(call)) {
PrintQuery.processAsync()
}
}
// Solution based on Thread-Local, not requiring suspending functions
get("/blocking") {
launch (coroutineContext + localCall.asContextElement(value = call)) {
PrintQuery.processBlocking()
}
}
}
intercept(ApplicationCallPipeline.ApplicationPhase.Call) {
call.respondText("Hé ho", ContentType.Text.Plain, HttpStatusCode.OK)
}
}
server.start(wait = true)
}
}
fun main() {
Main.start();
}
interface AsyncAddon {
/**
* Asynchronicity propagates in order to properly access coroutine execution information
*/
suspend fun processAsync();
}
interface BlockingAddon {
fun processBlocking();
}
object PrintQuery : AsyncAddon, BlockingAddon {
override suspend fun processAsync() = processRequest("async", fetchCurrentCallFromCoroutineContext())
override fun processBlocking() = processRequest("blocking", fetchCurrentCallFromThreadLocal())
private fun processRequest(prefix : String, call : ApplicationCall?) {
println("$prefix -> Query parameter: ${call?.parameters?.get("q") ?: "NONE"}")
}
}
/**
* Custom coroutine context allow to provide information about request execution.
*/
private class ApplicationCallContext(val call : ApplicationCall) : AbstractCoroutineContextElement(Key) {
companion object Key : CoroutineContext.Key<ApplicationCallContext>
}
/**
* This is your RequestUtils rewritten as a first-order function. It defines as asynchronous.
* If not, you won't be able to access coroutineContext.
*/
suspend fun fetchCurrentCallFromCoroutineContext(): ApplicationCall? {
// Here is where I am getting lost..
return coroutineContext.get(ApplicationCallContext.Key)?.call
}
fun fetchCurrentCallFromThreadLocal() : ApplicationCall? {
return localCall.get()
}
You can test it in your navigator:
http://localhost:8081/blocking?q=test1
http://localhost:8081/blocking?q=test2
http://localhost:8081/async?q=test3
server log output:
blocking -> Query parameter: test1
blocking -> Query parameter: test2
async -> Query parameter: test3
The key mechanism you want to use for this is the CoroutineContext. This is the place that you can set key value pairs to be used in any child coroutine or suspending function call.
I will try to lay out an example.
First, let us define a CoroutineContextElement that will let us add an ApplicationCall to the CoroutineContext.
class ApplicationCallElement(var call: ApplicationCall?) : AbstractCoroutineContextElement(ApplicationCallElement) {
companion object Key : CoroutineContext.Key<ApplicationCallElement>
}
Now we can define some helpers that will add the ApplicationCall on one of our routes. (This could be done as some sort of Ktor plugin that listens to the pipeline, but I don't want to add to much noise here).
suspend fun PipelineContext<Unit, ApplicationCall>.withCall(
bodyOfCall: suspend PipelineContext<Unit, ApplicationCall>.() -> Unit
) {
val pipeline = this
val appCallContext = buildAppCallContext(this.call)
withContext(appCallContext) {
pipeline.bodyOfCall()
}
}
internal suspend fun buildAppCallContext(call: ApplicationCall): CoroutineContext {
var context = coroutineContext
val callElement = ApplicationCallElement(call)
context = context.plus(callElement)
return context
}
And then we can use it all together like in this test case below where we are able to get the call from a nested suspending function:
suspend fun getSomethingFromCall(): String {
val call = coroutineContext[ApplicationCallElement.Key]?.call ?: throw Exception("Element not set")
return call.parameters["key"] ?: throw Exception("Parameter not set")
}
fun Application.myApp() {
routing {
route("/foo") {
get {
withCall {
call.respondText(getSomethingFromCall())
}
}
}
}
}
class ApplicationCallTest {
#Test
fun `we can get the application call in a nested function`() {
withTestApplication({ myApp() }) {
with(handleRequest(HttpMethod.Get, "/foo?key=bar")) {
assertEquals(HttpStatusCode.OK, response.status())
assertEquals("bar", response.content)
}
}
}
}

Clean way to access outer class by the implementing delegate class

I was thinking about such case (accessing outer class which uses current class to implement some stuff):
interface Does {
fun doStuff()
}
class ReallyDoes: Does {
var whoShouldReallyDo: Does? = null
override fun doStuff() {
println("Doing stuff instead of $whoShouldReallyDo")
}
}
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other.also { it.whoShouldReallyDo = this }, 42)
}
fun main(args: Array<String>) {
val worker = ReallyDoes()
val boss = MakesOtherDo(other = worker)
boss.doStuff()
}
Expected output:
Doing stuff instead of MakesOtherDo#28a418fc
But can't do that, because of error:
Error:(15, 79) Cannot access '' before superclass constructor
has been called
Which targets this statement: other.also { it.whoShouldReallyDo = this }
How can I (if at all) fix above implementation?
The reason for the error is other.also { ... = this } expression accesses this of type MakeOtherDo and is also used as argument to MakeOtherDo constructor. Hence, this will be accessed as part of MakeOtherDo (unary) constructor before this has been initialized as an instance of Does (super)class.
Since the assignment does not affect the initialization of the super class, you can executed it in the constructor of MakesOtherDo after the super class has been initialized.
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other, 42) {
other.also { it.whoShouldReallyDo = this }
}
}
It took me a few minutes to decipher what you were doing above, and really the problem has nothing to do with delegates. You can simplify it down to this:
class Wrapper(var any: Any? = null)
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper(this)) // Cannot access "<this>" before superclass constructor has been called
}
The concept of "this" doesn't exist yet when we're still generating arguments for its constructor. You just need to move the assignment into the block of the constructor, which is code that's run after this becomes available:
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper()){
wrapper.any = this
}
}
Or in the case of your example:
constructor(other: ReallyDoes): this(other, 42){
other.whoShouldReallyDo = this
}

Hiding base class constructor parameters in Kotlin

I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}