使用kotlin和jmockit

sk_*_*dev 8 junit jmockit kotlin

我需要一些使用jmockit和kotlin的建议.

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

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

(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));
    }
}
Run Code Online (Sandbox Code Playgroud)

(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));
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:

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)
Run Code Online (Sandbox Code Playgroud)

使用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:

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)
Run Code Online (Sandbox Code Playgroud)

编辑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));
    }
}
Run Code Online (Sandbox Code Playgroud)

使用kotlin和jmockit有没有更多的成功?

Rog*_*rio 3

我认为您无法使用 Kotlin 中的 JMockit(或大多数其他 JVM 替代语言,Groovy 可能除外),无论如何也不可靠。

原因是 1) JMockit 开发时并没有考虑到此类语言,也没有使用它们进行测试;2) 这些语言在编译为字节码时,会产生额外的或不同的结构,可能会混淆 JMockit 等工具;此外,他们通常会插入对自己内部 API 的调用,这也可能会造成妨碍。

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

就我个人而言,尽管我认识到这些语言带来的许多好处(而且我特别喜欢 Kotlin),但我还是宁愿坚持使用 Java(它在不断发展 - 请参阅 Java 8)。事实上,到目前为止,还没有任何替代 JVM 语言能够与 Java 的广泛使用相媲美,而且(在我看来)它们永远也不会。