JUnit – use kotlin and jmockit
I need some advice on using jmockit and kotlin
(cut) this is the (Java) class I tested:
public final class NutritionalConsultant { public static boolean isLunchTime() { int hour = LocalDateTime.Now().getHour(); return hour >= 12 && hour <= 14; } }
(j.1) this is a valid java test class
@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) however, the corresponding kotlin class throws an exception
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)); } }
Exceptions:
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)
Running with gradle throws the same exception
(KT. 2) using @ mocked syntax in kotlin, I got a different exception:
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)); } }
Exceptions:
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)
Edit 20150224 this may be related to "for simulated fields, instances of declaration types will be automatically created and assigned to fields by jmockit, provided that it is not final." (from http://jmockit.org/tutorial/BehaviorBasedTesting.html (from)
(KT. 3) however, change Val to VaR and use!! Operator causes a job test... But this is not the usual kotlin Code:
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)); } }
Are there any more successes with kotlin and jmockit?
Solution
I don't think you can use jmockit in kotlin (or most other JVM alternative languages, perhaps except groovy), which is unreliable anyway
The reason is that 1) jmockit did not consider these languages and did not test them; 2) These languages produce additional or different structures when compiled into bytecode, which may confuse tools such as jmockit; They often call their own internal APIs, which may also hinder them
In practice, alternative languages tend to develop their own tests / simulations / etc These tools not only apply to the language and its runtime, but also make full use of the advantages of the language
Personally, even if I can recognize the many benefits of these languages (I especially like kotlin), I'd rather stick to Java (it continues to evolve – see Java 8) In fact, so far, no other JVM language can approach the widespread use of Java, and (IMO) they will never