Created
April 6, 2019 15:05
-
-
Save daverix/866a116bbc4e71abeadfe30b1b04f5a9 to your computer and use it in GitHub Desktop.
kotlin home made mock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.daverix.mock | |
import com.google.common.truth.Truth.assertThat | |
import net.daverix.transparentcalendarwidget.db.EventsProvider | |
import net.daverix.transparentcalendarwidget.model.CalendarEvent | |
import org.junit.Test | |
import java.lang.reflect.InvocationHandler | |
import java.lang.reflect.Method | |
import java.lang.reflect.Proxy | |
class Test { | |
@Test | |
fun test() { | |
val myMock = mock<EventsProvider>() | |
val widget = createTestWidget(2) | |
myMock.calling("getEvents") { | |
parameter(0) { it == widget } | |
returns(emptyList<CalendarEvent>()) | |
} | |
val events = myMock.instance.getEvents(widget, emptyMap()) | |
assertThat(events).isNotNull() | |
myMock.verify("getEvents") { | |
parameter(0) { it == widget } | |
parameter(1) { it is Map<*, *> && it.isEmpty() } | |
returns { it is List<*> && it.isEmpty() } | |
} | |
} | |
} | |
interface Mock<T> { | |
val instance: T | |
fun verify(method: String, call: Call.() -> Unit) | |
fun calling(method: String, call: Call.() -> Unit) | |
} | |
interface Call { | |
fun parameter(index: Int, func: (Any?) -> Boolean) | |
fun returns(value: Any?) | |
fun returns(func: (Array<Any?>) -> Any?) | |
} | |
class Invocation(val name: String, | |
val args: Array<Any?>) | |
class UserCall : Call { | |
val parameterFuncs = mutableListOf<Pair<Int, (Any?) -> Boolean>>() | |
var returnFunc: ((Array<Any?>) -> Any?)? = null | |
override fun parameter(index: Int, func: (Any?) -> Boolean) { | |
parameterFuncs += index to func | |
} | |
override fun returns(value: Any?) { | |
returnFunc = { value } | |
} | |
override fun returns(func: (Array<Any?>) -> Any?) { | |
returnFunc = func | |
} | |
} | |
class UserFunction(val name: String, | |
val func: Call.() -> Unit) | |
inline fun <reified T> mock(): Mock<T> { | |
val calls = mutableListOf<Invocation>() | |
val userFunctions = mutableListOf<UserFunction>() | |
val invocationHandler = InvocationHandler { _: Any, method: Method, args: Array<Any?> -> | |
calls += Invocation(method.name, args) | |
val userCall = userFunctions | |
.filter { it.name == method.name } | |
.map { | |
val userCall = UserCall() | |
it.func(userCall) | |
userCall | |
} | |
.sortedByDescending { it.parameterFuncs.size } | |
.firstOrNull { | |
it.parameterFuncs.isEmpty() || | |
args.withIndex().all { (argIndex, value) -> | |
val func = it.parameterFuncs.filter { (paramIndex, _) -> paramIndex == argIndex } | |
.map { (_, func) -> func } | |
.firstOrNull() | |
func == null || func(value) | |
} | |
} | |
userCall?.returnFunc?.invoke(args) | |
} | |
val proxy = Proxy.newProxyInstance(T::class.java.classLoader, | |
arrayOf(T::class.java), | |
invocationHandler) as T | |
return object : Mock<T> { | |
override val instance: T = proxy | |
override fun verify(method: String, call: Call.() -> Unit) { | |
if (calls.isEmpty()) | |
throw AssertionError("No calls have been made on this mock") | |
if (method !in calls.map { it.name }) | |
throw AssertionError("method never called, however there was ${calls.size} other method calls") | |
val methods = calls.filter { it.name == method } | |
.filter { | |
val userCall = UserCall() | |
call(userCall) | |
userCall.parameterFuncs.isEmpty() || | |
it.args.withIndex().any { (argIndex, value) -> | |
val func = userCall.parameterFuncs.filter { (paramIndex, _) -> paramIndex == argIndex } | |
.map { (_, func) -> func } | |
.firstOrNull() | |
func != null && !func(value) | |
} | |
} | |
if(methods.isNotEmpty()) | |
throw AssertionError("${methods.size} method call(s) did not match:\n${methods.joinToString("\n") { | |
"${it.name}(${it.args.joinToString(", ")})" | |
}}") | |
} | |
override fun calling(method: String, call: Call.() -> Unit) { | |
userFunctions += UserFunction(method, call) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment