英文:
Kotlin How to mock generic class in unit test?
问题
我正在尝试在 Kotlin 中模拟 MongoCollection<Document> 类。
```kotlin
class MyTest {
val mockCollection: MongoCollection<Document> = mock(MongoCollection<Document>::class.java)
}
它会报错 只允许在类文字的左侧使用类。
在进行一些研究后,我找到了这个解答:
https://stackoverflow.com/questions/46401104/only-classes-are-allowed-on-the-left-hand-side-of-a-class-literal
我尝试为 MongoCollection
我还尝试将模拟对象强制转换为 Document,如下所示:
val mockCollection: MongoCollection<Document> = mock(MongoCollection::class.java) as MongoCollection<Document>
但是在代码实现内部访问 MongoCollection 时会抛出 NullpointerException 异常。
我已经尝试过以下两个库:
- Mockito Kotlin 库 - https://mvnrepository.com/artifact/com.nhaarman.mockitokotlin2/mockito-kotlin/2.2.0
- Java Mockito Core - https://mvnrepository.com/artifact/org.mockito/mockito-core/3.5.13
它们都出现了相同的错误。
我尝试在 Java 中编写相同的测试,泛型的强制转换在其中是有效的。
MongoCollection<Document> mockCollection = (MongoCollection<Document>) mock(MongoCollection.class);
有人有在 Kotlin 中模拟泛型类的经验吗?
<details>
<summary>英文:</summary>
I am trying to mock MongoCollection<Document> class in kotlin
class MyTest {
val mockCollection: MongoCollection<Document> = mock(MongoCollection<Document>::class.java)
}
it given an error **only classes are allowed on the left side of a class literal**
on researching a bit I found this
https://stackoverflow.com/questions/46401104/only-classes-are-allowed-on-the-left-hand-side-of-a-class-literal
I tried create a type for **MongoCollection<Document>** and then passing it to the mock but it gives an error as the mock is of **Type**.
I also tried casting the mock to Document as below
val mockCollection: MongoCollection<Document> = mock(MongoCollection::class.java) as MongoCollection<Document>
but that gives an **NullpointerException** exception during access of MongoCollection inside implementation of code.
I have tried both the
* Mockito kotlin library -https://mvnrepository.com/artifact/com.nhaarman.mockitokotlin2/mockito-kotlin/2.2.0
* Java mockito core - https://mvnrepository.com/artifact/org.mockito/mockito-core/3.5.13
and both of them have the same error?
I tired writing the same test in java and casting of generics work in it.
MongoCollection<Document> mockCollection = (MongoCollection<Document>) mock(MongoCollection.class);
Does anyone have any experience of mocking generic classes in Kotlin?
</details>
# 答案1
**得分**: 1
我为您编写了以下示例:
```kotlin
interface Mosi<T> {
fun mos(): T
}
然后下面的三个代码片段都适用于测试,测试都通过了:
class ExampleUnitTest {
val mosi = Mockito.mock(Mosi::class.java)
@Test
fun test() {
`when`(mosi.mos()).thenReturn("Mosi")
assertEquals(mosi.mos(), "Mosi")
}
}
class ExampleUnitTest {
val mosi = Mockito.mock(Mosi::class.java) as Mosi<String>
@Test
fun test() {
`when`(mosi.mos()).thenReturn("Mosi")
assertEquals(mosi.mos(), "Mosi")
}
}
class ExampleUnitTest {
val mosi = mock<Mosi<String>> {
on { mos() }
.thenReturn("Mosi")
}
@Test
fun test() {
assertEquals(mosi.mos(), "Mosi")
}
}
如果出现了 NPE
(空指针异常),问题可能出在其他地方,也许提供更多的代码可以帮助解决问题!
英文:
I wrote the following example for you:
interface Mosi<T> {
fun mos(): T
}
then all three code snippets below work for testing and test are passed:
class ExampleUnitTest {
val mosi = Mockito.mock(Mosi::class.java)
@Test
fun test() {
`when`(mosi.mos()).thenReturn("Mosi")
assertEquals(mosi.mos(), "Mosi")
}
}
class ExampleUnitTest {
val mosi = Mockito.mock(Mosi::class.java) as Mosi<String>
@Test
fun test() {
`when`(mosi.mos()).thenReturn("Mosi")
assertEquals(mosi.mos(), "Mosi")
}
}
class ExampleUnitTest {
val mosi = mock<Mosi<String>> {
on { mos() }
.thenReturn("Mosi")
}
@Test
fun test() {
assertEquals(mosi.mos(), "Mosi")
}
}
if you get NPE
the problem is somewhere else, maybe providing more code can help!
答案2
得分: 0
解决方案
---
创建一个类似于 Mockito 的扩展:
inline fun <reified T: Any> mock() = Mockito.mock(T::class.java)
用法
---
像这样使用扩展函数:
val mockCollection = mock<MongoCollection<Document>>()
val mockCollection: MongoCollection<Document> = mock() // 我更喜欢这个
我总是使用这个而不是原始的 `mock()` 函数,因为可以推断出 Java 类。节省了一些输入。
题外话
---
甚至用于模拟 Lambdas 也非常好!
val callback: () -> Unit = mock()
someClass.doSomething(callback)
verify(callback).invoke()
英文:
Solution
Create an extension on Mockito like this:
inline fun <reified T: Any> mock() = Mockito.mock(T::class.java)
Usage
Use the extension function like this:
val mockCollection = mock<MongoCollection<Document>>()
val mockCollection: MongoCollection<Document> = mock() // I prefer this one
I always use this instead of the original mock()
function since the java class can be inferred. Saves some typing.
Off-topic
It's even great for mocking Lambdas!
val callback: () -> Unit = mock()
someClass.doSomething(callback)
verify(callback).invoke()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论