Skip to content

Instantly share code, notes, and snippets.

@parthdave93
Last active November 6, 2019 06:23
Show Gist options
  • Save parthdave93/a3ee2241cd118fe0eb5990bbfb904301 to your computer and use it in GitHub Desktop.
Save parthdave93/a3ee2241cd118fe0eb5990bbfb904301 to your computer and use it in GitHub Desktop.
Mockito mock custom made mock class
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.parthdave93"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
testImplementation 'org.mockito:mockito-core:1.10.19'
testImplementation 'org.mockito:mockito-all:1.10.19'
}
import com.com.parthdave93.mock.Foo
import com.com.parthdave93.mock.FooInterface
import com.com.parthdave93.ownmockingmodule.MockDave
import org.mockito.Mockito
object CustomMockitoTestSuit {
@JvmStatic
fun main(args: Array<String>) {
// java.lang.reflect.Proxy
println("# CustomMockProxy By Parth Dave")
val fooInterfaceMock = CustomMockProxy.mock(FooInterface::class.java)
CustomMockProxy.`when`(fooInterfaceMock.foo()).thenReturn("Foo Fighters!")
println(fooInterfaceMock.foo())
CustomMockProxy.`when`(fooInterfaceMock.echo("echo")).thenReturn("echo")
println(fooInterfaceMock.echo("echo"))
CustomMockProxy.`when`(fooInterfaceMock.echo("hello")).thenReturn("world")
println(fooInterfaceMock.echo("hello"))
println()
}
}
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import java.util.ArrayList
import java.util.Arrays
class CustomMockProxy {
companion object {
private var lastMockInvocationHandler: MockInvocationHandler? = null
/**
* Creates a mock based on a class.
*
* @param clazz the class of the mock
* @param <T> the type of the mock
* @return the mock object
</T> */
fun <T> mock(clazz: Class<T>): T {
val invocationHandler = MockInvocationHandler()
return Proxy.newProxyInstance(
MockProxy::class.java.classLoader,
arrayOf<Class<*>>(clazz),
invocationHandler
) as T
}
/**
* This class is just needed to ERHALTEN the type information. So that we
* have the type information for the When::thenReturn method.
*
* @param obj the value which we doesn't need.
* @param <T> the type of the return value
* @return an instance of When with the correct type information
</T> */
fun <T> `when`(obj: T?): When {
return When()
}
}
class When{
/**
* Sets the return value for the last method call.
*
* @param retObj the return value
*/
fun thenReturn(retObj: Any) {
lastMockInvocationHandler!!.setRetObj(retObj)
}
}
private class MockInvocationHandler : InvocationHandler {
private var lastMethod: Method? = null
private var lastArgs: Array<Any>? = null
private val dataHolders = ArrayList<DataHolder>()
/**
* Intercepts the method call and decides what value will be returned.
*/
@Throws(Throwable::class)
override fun invoke(proxy: Any?, method: Method?, args: Array<Any>?): Any? {
lastMockInvocationHandler = this
lastMethod = method
lastArgs = args
// checks if the method was already called with the given arguments
for (dataHolder in dataHolders) {
if (dataHolder.method == method && Arrays.deepEquals(dataHolder.args, args)) {
// if so than return the stored value
return dataHolder.retObj
}
}
// otherwise return null
return null
}
/**
* Adds the return value for the last called method with the last given arguments.
*
* @param retObj the return value
*/
fun setRetObj(retObj: Any?) {
var isFound = false
for (dataHolder in dataHolders) {
if (dataHolder.method == lastMethod && Arrays.deepEquals(
dataHolder.args,
lastArgs
)
) {
dataHolder.retObj = retObj
isFound = true
}
}
if (!isFound)
dataHolders.add(DataHolder(lastMethod, lastArgs, retObj))
}
/**
* Stores the method with it's arguments and the return value.
*/
inner class DataHolder(
val method: Method?,
val args: Array<Any>?,
var retObj: Any?
)
}
}
# MockProxy
Foo Fighters!
echo
world
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment