Spock 使用 Mockito 测试 Kotlin 类 [英] Spock with Mockito testing Kotlin classes

查看:77
本文介绍了Spock 使用 Mockito 测试 Kotlin 类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些用 Spock 编写的测试,其中涵盖了我的 Java 代码.现在我迁移到 Kotlin,问题是我无法模拟最终课程,所以我决定使用这里描述的 Mockito 插件:https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#unmockable

I have some tests written in Spock which covers my Java code. Now I migrate to Kotlin and the problem is i cannot mock final classes so i decide to use Mockito plugin described here: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#unmockable

问题是我需要用 Mockitos 的 any()、anyString()、when()、then() 等替换每个 '_' '>>' 吗?我尝试使用 Mockito 模拟最终课程,但似乎不起作用.

The question is do I need to replace every '_' '>>' with Mockitos' any(), anyString(), when(), then() etc? I tried to just mock final classes using Mockito but it seems not work.

如果我必须替换在这种情况下使用 Spock 测试框架的优势是什么?也许我应该删除它并只使用 Mockito?

If i have to replace what the advantage is for using Spock testing framework in this case? Maybe i should remove it and stay with Mockito only?

推荐答案

我不使用 Kotlin,但我之前使用过 PowerMock 来模拟最终的类/方法和静态方法.我想知道是否可以使用 Spock 的 GroovyMock 和全局 GroovySpy 特性,并使用 Spock 1.1-groovy-2.4 对 Java 代码进行测试.在第一快速 &肮脏的测试场景似乎有效:

I do not use Kotlin, but I have used PowerMock before for mocking final classes/methods and static methods. I was wondering about whether it might be possible to use Spock's GroovyMock and global GroovySpy features and tested it against Java code using Spock 1.1-groovy-2.4. In a first quick & dirty test scenario it seems to work:

被测Java类:

package de.scrum_master.stackoverflow;

public final class FinalClass {
  public static final String finalStaticMethod() {
    return "x";
  }

  public final String finalMethod() {
    return "x";
  }
}

Spock 测试:

package de.scrum_master.stackoverflow

import spock.lang.Specification

/**
 * See https://stackoverflow.com/q/48391716/1082681
 * See http://spockframework.org/spock/docs/1.1/all_in_one.html#GroovyMocks
 */
class FinalClassTest extends Specification {
  def "use GroovyMock for final method in final class"() {
    given:
    FinalClass finalClass = GroovyMock() {
      finalMethod() >> "mocked"
    }

    expect:
    finalClass.finalMethod() == "mocked"
  }

  def "use global GroovySpy for final static method in final class"() {
    given:
    GroovySpy(FinalClass, global: true)
    FinalClass.finalStaticMethod() >> "mocked"

    expect:
    FinalClass.finalStaticMethod() == "mocked"
  }
}

对我来说,在运行测试时,两个特征方法都是绿色的.也许你想用我的例子试一试,然后用你的 Kotlin 类试试——不过,我不能保证后者.

For me both feature methods were green when running the test. Maybe you want to give it a try with my example and subsequently with your Kotlin classes - no guarantees for the latter from me, though.

注意:Spock 手册说:

当从 Java 代码调用时,Groovy 模拟的行为与常规模拟一样.

When called from Java code, Groovy mocks will behave like regular mocks.

因此,当将 Groovy Mocks 作为依赖项注入被测 Java 类时,您可能会感到失望.

So maybe you will get disappointed when injecting Groovy Mocks as dependencies into Java classes under test.

更新:好的,我用另一个 Java 类使用那些花哨的 GroovyMocks 测试了它 - 如上所述 - 它不起作用:

Update: Okay, I tested it with another Java class using those fancy GroovyMocks and - as mentioned above - it does not work:

使用模拟类作为依赖项的 Java 类:

package de.scrum_master.stackoverflow;

public class AnotherClass {
  public String doSomething(FinalClass finalClass) {
    return finalClass.finalMethod();
  }

  public String doSomethingElse() {
    return FinalClass.finalStaticMethod();
  }
}

Spock 测试:

package de.scrum_master.stackoverflow

import spock.lang.Specification

/**
 * See https://stackoverflow.com/q/48391716/1082681
 * See http://spockframework.org/spock/docs/1.1/all_in_one.html#GroovyMocks
 */
class AnotherClassTest extends Specification {
  def "indirectly use GroovyMock for final method in final class"() {
    given:
    FinalClass finalClass = GroovyMock() {
      finalMethod() >> "mocked"
    }

    expect:
    new AnotherClass().doSomething(finalClass) == "mocked"
  }

  def "indirectly use global GroovySpy for final static method in final class"() {
    given:
    GroovySpy(FinalClass, global: true)
    FinalClass.finalStaticMethod() >> "mocked"

    expect:
    new AnotherClass().doSomethingElse() == "mocked"
  }
}

不幸的是,两个测试都失败,因为从 Java 类中使用这些方法时不会被存根.即你被 PowerMock 或 Mockito 困住了.但是您仍然可以使用所有其他优秀的 Spock 功能,例如数据表、@Unroll 等等.

Unfortunately, both tests fail because the methods do not get stubbed when used from the Java class. I.e. you are stuck with PowerMock or Mockito. But still you can use all the other nice Spock features such as data tables, @Unroll and many more.

更新 2:解决方案

将此添加到您的 Maven 构建中(如果您使用 Gradle,请执行类似操作):

Add this to your Maven build (if you use Gradle, do something similar):

<dependency>
  <groupId>de.jodamob.kotlin</groupId>
  <artifactId>kotlin-runner-spock</artifactId>
  <version>0.3.1</version>
  <scope>test</scope>
</dependency>

现在您可以使用项目 kotlin-testrunner 中的 SpotlinTestRunner结合注释如

Now you can use the SpotlinTestRunner from project kotlin-testrunner in combination with annotations like

  • @OpenedClasses([Foo, Bar, Zot])
  • @OpenedPackages(["de.scrum_master.stackoverflow", "my.other.package"])

当然这不适用于静态方法(您仍然需要 PowerMock),但您的问题是关于封闭 Kotlin 类中的非静态方法.使用这个测试运行器,你可以模拟它们,因为一个特殊的类加载器在测试执行之前通过 Javassist 打开它们:

Of course this will not work for static methods (you still need PowerMock for it), but your question was about non-static methods in closed Kotlin classes. With this test runner you can just mock them because a special classloader opens them up via Javassist before test execution:

package de.scrum_master.stackoverflow

import de.jodamob.kotlin.testrunner.OpenedClasses
import de.jodamob.kotlin.testrunner.OpenedPackages
import de.jodamob.kotlin.testrunner.SpotlinTestRunner
import org.junit.runner.RunWith
import spock.lang.Specification

/**
 * See https://stackoverflow.com/q/48391716/1082681
 * See https://github.com/dpreussler/kotlin-testrunner
 */
@RunWith(SpotlinTestRunner)
@OpenedClasses(FinalClass)
//@OpenedPackages("de.scrum_master.stackoverflow")
class AnotherClassSpotlinRunnerTest extends Specification {
  def "use SpotlinRunner to stub final method in final class"() {
    given:
    FinalClass finalClass = Stub() {
      finalMethod() >> "mocked"
    }

    expect:
    new AnotherClass().doSomething(finalClass) == "mocked"
  }
}

这篇关于Spock 使用 Mockito 测试 Kotlin 类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆