Spock与Mockito测试Kotlin课程

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

问题是我需要用Mockitos的any(),anyString(),when(),then()等替换每个’_”>>’吗? 我试图用Mockito来模拟最终的类,但它似乎不工作。

如果我必须替换这种情况下使用Spock测试框架的好处吗? 也许我应该删除它,只留在Mockito?

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

测试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课程 – 尽管如此,没有后者的保证。


注意: Spock手册说:

当从Java代码中调用时,Groovy mocks的行为就像普通的mock一样。

所以,当将Groovy Mocks作为依赖关系注入测试的Java类时,您可能会感到失望。


更新:好吧,我用另一个Java类来测试它,使用那些花哨的GroovyMocks和 – 如上所述 – 它不工作:

使用模拟类作为依赖的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中。 但是,您仍然可以使用其他所有Spockfunction,例如数据表, @Unroll等等。


更新2:解决方案

添加到你的Maven构建(如果你使用Gradle,做类似的事情):

  de.jodamob.kotlin kotlin-runner-spock 0.3.1 test  

现在,您可以使用项目kotlin-testrunner中的SpotlinTestRunner与注释类似的组合

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

当然这对于静态方法来说不起作用(你仍然需要PowerMock),但是你的问题是关于Kotlin类的非静态方法。 有了这个测试运行器,你可以嘲笑它们,因为一个特殊的类加载器在测试执行之前通过Javassist打开它们:

 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" } }