Kotlin如何在单元测试中模拟泛型类?

huangapple go评论99阅读模式
英文:

Kotlin How to mock generic class in unit test?

问题

  1. 我正在尝试在 Kotlin 中模拟 MongoCollection<Document>
  2. ```kotlin
  3. class MyTest {
  4. val mockCollection: MongoCollection<Document> = mock(MongoCollection<Document>::class.java)
  5. }

它会报错 只允许在类文字的左侧使用类

在进行一些研究后,我找到了这个解答:
https://stackoverflow.com/questions/46401104/only-classes-are-allowed-on-the-left-hand-side-of-a-class-literal
我尝试为 MongoCollection 创建一个类型,然后将其传递给模拟对象,但是它会报错,因为模拟对象是 Type 类型。

我还尝试将模拟对象强制转换为 Document,如下所示:

  1. val mockCollection: MongoCollection<Document> = mock(MongoCollection::class.java) as MongoCollection<Document>

但是在代码实现内部访问 MongoCollection 时会抛出 NullpointerException 异常。

我已经尝试过以下两个库:

它们都出现了相同的错误。

我尝试在 Java 中编写相同的测试,泛型的强制转换在其中是有效的。

  1. MongoCollection<Document> mockCollection = (MongoCollection<Document>) mock(MongoCollection.class);

有人有在 Kotlin 中模拟泛型类的经验吗?

  1. <details>
  2. <summary>英文:</summary>
  3. I am trying to mock MongoCollection&lt;Document&gt; class in kotlin

class MyTest {

val mockCollection: MongoCollection<Document> = mock(MongoCollection<Document>::class.java)

}

  1. it given an error **only classes are allowed on the left side of a class literal**
  2. on researching a bit I found this
  3. https://stackoverflow.com/questions/46401104/only-classes-are-allowed-on-the-left-hand-side-of-a-class-literal
  4. I tried create a type for **MongoCollection&lt;Document&gt;** and then passing it to the mock but it gives an error as the mock is of **Type**.
  5. I also tried casting the mock to Document as below

val mockCollection: MongoCollection<Document> = mock(MongoCollection::class.java) as MongoCollection<Document>

  1. but that gives an **NullpointerException** exception during access of MongoCollection inside implementation of code.
  2. I have tried both the
  3. * Mockito kotlin library -https://mvnrepository.com/artifact/com.nhaarman.mockitokotlin2/mockito-kotlin/2.2.0
  4. * Java mockito core - https://mvnrepository.com/artifact/org.mockito/mockito-core/3.5.13
  5. and both of them have the same error?
  6. I tired writing the same test in java and casting of generics work in it.

MongoCollection<Document> mockCollection = (MongoCollection<Document>) mock(MongoCollection.class);

  1. Does anyone have any experience of mocking generic classes in Kotlin?
  2. </details>
  3. # 答案1
  4. **得分**: 1
  5. 我为您编写了以下示例:
  6. ```kotlin
  7. interface Mosi<T> {
  8. fun mos(): T
  9. }

然后下面的三个代码片段都适用于测试,测试都通过了:

  1. class ExampleUnitTest {
  2. val mosi = Mockito.mock(Mosi::class.java)
  3. @Test
  4. fun test() {
  5. `when`(mosi.mos()).thenReturn("Mosi")
  6. assertEquals(mosi.mos(), "Mosi")
  7. }
  8. }
  1. class ExampleUnitTest {
  2. val mosi = Mockito.mock(Mosi::class.java) as Mosi<String>
  3. @Test
  4. fun test() {
  5. `when`(mosi.mos()).thenReturn("Mosi")
  6. assertEquals(mosi.mos(), "Mosi")
  7. }
  8. }
  1. class ExampleUnitTest {
  2. val mosi = mock<Mosi<String>> {
  3. on { mos() }
  4. .thenReturn("Mosi")
  5. }
  6. @Test
  7. fun test() {
  8. assertEquals(mosi.mos(), "Mosi")
  9. }
  10. }

如果出现了 NPE(空指针异常),问题可能出在其他地方,也许提供更多的代码可以帮助解决问题!

英文:

I wrote the following example for you:

  1. interface Mosi&lt;T&gt; {
  2. fun mos(): T
  3. }

then all three code snippets below work for testing and test are passed:

  1. class ExampleUnitTest {
  2. val mosi = Mockito.mock(Mosi::class.java)
  3. @Test
  4. fun test() {
  5. `when`(mosi.mos()).thenReturn(&quot;Mosi&quot;)
  6. assertEquals(mosi.mos(), &quot;Mosi&quot;)
  7. }
  8. }
  1. class ExampleUnitTest {
  2. val mosi = Mockito.mock(Mosi::class.java) as Mosi&lt;String&gt;
  3. @Test
  4. fun test() {
  5. `when`(mosi.mos()).thenReturn(&quot;Mosi&quot;)
  6. assertEquals(mosi.mos(), &quot;Mosi&quot;)
  7. }
  8. }
  1. class ExampleUnitTest {
  2. val mosi = mock&lt;Mosi&lt;String&gt;&gt; {
  3. on { mos() }
  4. .thenReturn(&quot;Mosi&quot;)
  5. }
  6. @Test
  7. fun test() {
  8. assertEquals(mosi.mos(), &quot;Mosi&quot;)
  9. }
  10. }

if you get NPE the problem is somewhere else, maybe providing more code can help!

答案2

得分: 0

  1. 解决方案
  2. ---
  3. 创建一个类似于 Mockito 的扩展:
  4. inline fun <reified T: Any> mock() = Mockito.mock(T::class.java)
  5. 用法
  6. ---
  7. 像这样使用扩展函数:
  8. val mockCollection = mock<MongoCollection<Document>>()
  9. val mockCollection: MongoCollection<Document> = mock() // 我更喜欢这个
  10. 我总是使用这个而不是原始的 `mock()` 函数,因为可以推断出 Java 类。节省了一些输入。
  11. 题外话
  12. ---
  13. 甚至用于模拟 Lambdas 也非常好!
  14. val callback: () -> Unit = mock()
  15. someClass.doSomething(callback)
  16. verify(callback).invoke()
英文:

Solution

Create an extension on Mockito like this:

  1. inline fun &lt;reified T: Any&gt; mock() = Mockito.mock(T::class.java)

Usage

Use the extension function like this:

  1. val mockCollection = mock&lt;MongoCollection&lt;Document&gt;&gt;()
  2. val mockCollection: MongoCollection&lt;Document&gt; = 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!

  1. val callback: () -&gt; Unit = mock()
  2. someClass.doSomething(callback)
  3. verify(callback).invoke()

huangapple
  • 本文由 发表于 2020年10月16日 22:50:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/64391483.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定