我需要一些使用jmockit和kotlin的建议。
(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 这可能与&#34有关;对于模拟字段,声明类型的实例将由JMockit自动创建并分配给字段,前提是它是&#34; s不是最终的。&#34; (来自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));
}
}
使用kotlin和jmockit有没有更多的成功?
答案 0 :(得分:2)
我不认为您能够使用Kotlin中的JMockit(或大多数其他JVM替代语言,可能除了Groovy),无论如何都不可靠。
原因是1)JMockit并没有考虑到这些语言而开发,也没有用它们进行测试; 2)这些语言在编译为字节码时会产生额外的或不同的结构,这些结构可能会混淆像JMockit这样的工具;他们通常也会插入对自己内部API的调用,这也可能妨碍他们。
在实践中,替代语言倾向于开发自己的测试/模拟/等。这些工具不仅适用于该语言及其运行时,而且还可以充分利用语言的优势。
就个人而言,即使我能够认识到这些语言带来的诸多好处(我特别喜欢Kotlin),我宁愿坚持使用Java(它继续发展 - 参见Java 8)。事实是,到目前为止, no 替代JVM语言已经接近Java的广泛使用,而且(IMO)它们永远不会。
答案 1 :(得分:0)
我们进行了一些实验,发现你可以定义这样的特殊功能:
fun uninitialized<T>() = null as T
然后像这样使用它:
[Mocked] val dateTime : LocalDateTime = uninitialized()
您也可以使用它而不是Matchers.any()
来获得相同的效果。
我们将考虑将其添加到编译器或标准库中。