Kotlin Mockito Generics



假设我的类是:

open class TestThis{
@Autowired
private var myService : MyService? = null
fun doMyFunction(){
val result = myService.doSomething("hello world", Function { entry ->
var retVal : Boolean = false
//some processing
retVal
})
}
}
@Service
open class MyService{
fun doSomething(str1 : String, java.util.Function<MyCrap, Boolean>) : List<String>{
//do something here
}
}

@RunWith(MockitoJUnitRunner::class)
class TestThisTest{
@Mock
var myService : MyService? = null
@InjectMocks
var test : TestThis? = null
@Before
fun before(){
val list : List<String> = //init list
//this line causes compilation error due to generics. error 1
Mockito.`when`(myService.doSomething(Mockito.anyString(), Mockito.any(Function::class.java))).thenReturn(list)
//this line also causes compilation error due to generics. error 2
Mockito.`when`(myService.doSomething(Mockito.anyString(), Mockito.any(Function<MyCrap, Boolean>::class.java))).thenReturn(list)
}
}

错误1:

类型推理失败。预期的类型不匹配。

错误2:

在类文字的左侧只允许使用类

那么,我如何模拟myService#doSomething

让匹配器与Kotlin一起工作可能是个问题。

  • 如果您有一个用Kotlin编写的方法,它不接受可为null的参数,那么我们无法使用Mockito.any()与之匹配。这是因为它返回null,并且这不可分配给不可为null的参数
  • 在Kotlin类和成员默认为final的情况下,我们需要打开它们,因为final方法禁止mocking
  • 泛型类模拟上升错误,如您所描述的Only classes are allowed on the left hand side of a class literal

所有这些问题都可以通过简单的MockitoUtils类来解决:

object MockitoUtils {
inline fun <reified T> anyObject(): T {
return Mockito.any(T::class.java) ?: createInstance()
}
inline fun <reified T : Any> createInstance(): T {
return when (T::class) {
Boolean::class -> false as T
Byte::class -> 0.toByte() as T
Char::class -> 0.toChar() as T
Short::class -> 0.toShort() as T
Int::class -> 0 as T
Long::class -> 0L as T
Float::class -> 0f as T
Double::class -> 0.0 as T
else -> createInstance(T::class)
}
}
fun <T : Any> createInstance(kClass: KClass<T>): T {
return castNull()
}
@Suppress("UNCHECKED_CAST")
private fun <T> castNull(): T = null as T
}

用法示例:

Mockito.`when`(myService!!.doSomething(Mockito.anyString(), MockitoUtils.anyObject())).thenReturn(list)

模拟服务:

open class MyService {
open fun doSomething(str1 : String, func : java.util.function.Function<MyCrap, Boolean>) : List<String>{
return emptyList()
}
}

测试服务:

open class TestThis{
private var myService : MyService? = null
fun doMyFunction() : List<String>? {
val result = myService?.doSomething("hello world", java.util.function.Function { entry ->
var retVal : Boolean = false
//some processing
retVal
} )
return result;
}
}

测试实施:

import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnitRunner
import kotlin.reflect.KClass
@RunWith(MockitoJUnitRunner::class)
class TestThisTest{
@Mock
var myService : MyService? = null
@InjectMocks
var test : TestThis? = null
@Before
fun before(){
val list : ArrayList<String> = arrayListOf()
list.add("123")
val thenReturn = Mockito.`when`(myService!!.doSomething(Mockito.anyString(), MockitoUtils.anyObject())).thenReturn(list)
}
@Test
fun test() {
val list = test!!.doMyFunction()
Assert.assertTrue(list!!.contains("123"))
}
object MockitoUtils {
inline fun <reified T> anyObject(): T {
return Mockito.any(T::class.java) ?: createInstance()
}
inline fun <reified T : Any> createInstance(): T {
return when (T::class) {
Boolean::class -> false as T
Byte::class -> 0.toByte() as T
Char::class -> 0.toChar() as T
Short::class -> 0.toShort() as T
Int::class -> 0 as T
Long::class -> 0L as T
Float::class -> 0f as T
Double::class -> 0.0 as T
else -> createInstance(T::class)
}
}
fun <T : Any> createInstance(kClass: KClass<T>): T {
return castNull()
}
@Suppress("UNCHECKED_CAST")
private fun <T> castNull(): T = null as T
}
}

替代解决方案:
另一个可能的解决方案是使用类似mockito kotlin的库。
Maven:

<dependency>
<groupId>org.mockito.kotlin</groupId>
<artifactId>mockito-kotlin</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>

你不应该嘲笑"TestThis";当您尝试测试此服务内部的某些内容时。如果你嘲笑它,就什么都没有;内部";。这只是一个模拟。尝试安装它,然后注入MyService的模拟。

你在哪里写测试也很奇怪。为什么在测试类TestThisTest中对MyService进行单元测试。您应该为MyService创建自己的单元测试。

相关内容

  • 没有找到相关文章

最新更新