I need some advice using jmockit with kotlin.
(CUT) This is my (Java) class under the test:
public final class NutritionalConsultant { public static boolean isLunchTime() { int hour = LocalDateTime.now().getHour(); return hour >= 12 && hour <= 14; } }
(j.1) This is a working 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)); } }
An exception:
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)
The same exception occurs when starting with gradle.
(kt.2) Using @Mocked syntax with kotlin, I get another 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)); } }
An exception:
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, perhaps this is due to "For a dummy field, an instance of the declared type will be automatically created by JMockit and assigned to this field if it is not final." (from http://jmockit.org/tutorial/BehaviorBasedTesting.html )
(kt.3) However, changing val to var and using a !! the statement leads to a working test ... but this is not the idiomatic 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 you more likely to use kotlin with jmockit?