与jmockit一起使用kotlin

我需要一些建议,使用kotlin使用jmockit。

(CUT)这是我的(Java)测试类:

public final class NutritionalConsultant { public static boolean isLunchTime() { int hour = LocalDateTime.now().getHour(); return hour >= 12 && hour <= 14; } } 

(j.1)这是一个正在运行的Java测试类

 @RunWith(JMockit.class) public class NutritionalConsultantTest { @Test public void shouldReturnTrueFor12h(@Mocked final LocalDateTime dateTime) { new Expectations() {{ LocalDateTime.now(); result = dateTime; dateTime.getHour(); result = 12; }}; boolean isLunchTime = NutritionalConsultant.isLunchTime(); assertThat(isLunchTime, is(true)); } } 

(kt.1)但是,相应的kotlin类抛出一个异常

 RunWith(javaClass<JMockit>()) public class NutritionalConsultantKt1Test { Test public fun shouldReturnTrueFor12h(Mocked dateTime : LocalDateTime) { object : Expectations() {{ LocalDateTime.now(); result = dateTime; dateTime.getHour(); result = 12; }} val isLunchTime = NutritionalConsultant.isLunchTime() assertThat(isLunchTime, eq(true)); } } 

例外:

 java.lang.Exception: Method shouldReturnTrueFor12h should have no parameters at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:408) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:41) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

使用gradle运行时会抛出同样的异常。

(kt.2)在kotlin中使用@Mocked语法我得到了一个不同的异常:

 RunWith(javaClass<JMockit>()) public class NutritionalConsultantKt2Test { Mocked var dateTime : LocalDateTime by Delegates.notNull() Test public fun shouldReturnTrueFor12h() { object : Expectations() {{ LocalDateTime.now(); result = dateTime; dateTime.getHour(); result = 12; }} val isLunchTime = NutritionalConsultant.isLunchTime() assertThat(isLunchTime, eq(true)); } } 

例外:

 java.lang.IllegalArgumentException: Final mock field "dateTime$delegate" must be of a class type at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

编辑20150224也许这是相关的“对于模拟字段,声明的类型的实例将自动创建的JMockit并分配给该字段,只要它不是最终的。 (来自http://jmockit.org/tutorial/BehaviorBasedTesting.html )

(kt.3)然而,改变val为var和使用! 运算符导致一个工作测试…但这不是惯用的kotlin代码:

 RunWith(javaClass<JMockit>()) public class NutritionalConsultantKt3Test { Mocked var dateTime : LocalDateTime? = null Test public fun shouldReturnTrueFor12h() { object : Expectations() {{ LocalDateTime.now(); result = dateTime; dateTime!!.getHour(); result = 12; }} val isLunchTime = NutritionalConsultant.isLunchTime() assertThat(isLunchTime, eq(true)); } } 

使用jmockit使用kotlin有更多的成功吗?

我不认为你可以使用Kotlin的JMockit(或者大多数其他的JVM替代语言,Groovy可能是个例外),而不是可靠的。

原因是1)JMockit不是用这种语言开发的,并没有经过测试。 2)这些语言在编译为字节码时会产生额外的或不同的结构,这些结构可能会混淆像JMockit这样的工具; 而且他们通常会将调用插入到自己的内部API中,这也可能会阻碍他们。

在实践中,替代语言倾向于开发他们自己的测试/嘲笑/等等。 工具,它不仅适用于该语言及其运行时,还可以充分利用该语言的优势。

就个人而言,尽管我可以认识到这些语言带来的许多好处(我特别喜欢Kotlin),但我宁愿坚持使用Java(它将继续发展 – 参见Java 8)。 事实上,到目前为止,Java的广泛使用还没有替代JVM语言,而(IMO)他们永远不会。

我们已经尝试了一下,发现可以像这样定义特殊的功能:

 fun uninitialized<T>() = null as T 

然后像这样使用它:

 [Mocked] val dateTime : LocalDateTime = uninitialized() 

你也可以用它来代替Matchers.any()来达到同样的效果。 我们将考虑将其添加到编译器或标准库。