Using kotlin with jmockit

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?

+6
source share
2 answers

I don’t think you can use JMockit from Kotlin (or most other alternative JVM languages, with the possible exception of Groovy), but not reliably.

The reasons are as follows: 1) JMockit was not designed with such languages ​​in mind and was not tested with them; and 2) these languages, when compiled into bytecode, create additional or different constructs that may confuse the tool, such as JMockit; they also typically insert calls into their own APIs, which can also interfere.

In practice, alternative languages ​​tend to develop their own testing / bullying, etc. tools that not only work well for this language and its runtime, but also allow you to take full advantage of the language.

Personally, although I can recognize the many benefits that such languages ​​bring (and I especially love Kotlin), I would rather stick with Java (which continues to evolve - see Java 8). The fact is that so far no alternative JVM language has come even close to the widely used Java, and (IMO) they will never be.

+2
source

We experimented a bit and found that you can define a special function as follows:

 fun uninitialized<T>() = null as T 

and then use it like this:

 [Mocked] val dateTime : LocalDateTime = uninitialized() 

You can also use it instead of Matchers.any() for the same effect. We will consider adding it to the compiler or standard library.

0
source

Source: https://habr.com/ru/post/982939/


All Articles