3
votes

I'm busy converting Java8 Junit tests to Kotlin

Java8:

@ActiveProfiles("junit")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:META-INF/spring/applicationContext.xml"})
public class AuctionTest {

    @Autowired
    AccountProcessor ap;

    @Test
    @Rollback
    public void securityTest(){

Rewriting it in Kotlin, it looks like this:

@ActiveProfiles("junit")
@RunWith(SpringJUnit4ClassRunner::class)
@ContextConfiguration("classpath*:META-INF/spring/applicationContext.xml")
class AccountTest() {

    @Autowired
    lateinit var ap: AccountProcessor

    @Test
    @Rollback
    fun securityTest() {

The above unit test runs fine, but I want to get rid of the lateinit

Rewriting it like this:

@ActiveProfiles("junit")
@RunWith(SpringJUnit4ClassRunner::class)
@ContextConfiguration("classpath*:META-INF/spring/applicationContext.xml")
class AccountTest(@Autowired val ap: AccountProcessor) {

    @Test
    @Rollback
    fun securityTest() {

And Junit complains

java.lang.Exception: Test class should have exactly one public zero-argument constructor

at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.(SpringJUnit4ClassRunner.java:104) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29) at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26) at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:31) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:96) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Is there a way around this or am I stuck with lateinit @Autowires ?

1
1. There's nothing wrong with having properties as lateinit. The reason why lateinit keyword was created, is to handle such cases. I don't see any reasons why you'd want to get rid of lateinit. 2. As the exception message reads, you need to have a no-arg constructor, so it's impossible to have @Autowired constructor args.rafal
I don't think what you want is possible without some tinkering in Junit. If you do want to go that road, you'll need to build your own Runner that initialises spring and then instantiates the test class by calling the constructor. Take a look at the Parameterized to see how to instantiate a test class that requires parameters.Augusto
Fair enough, seems like the easiest route is to just leave lateinit in there for now.Jan Vladimir Mostert

1 Answers

2
votes

In case of spring component to inject processor you should annotate constructor, not constructor argument:

@Service
class AccountTest @Autowired constructor(val ap: AccountProcessor) {
}

Bit Junit adds their restrictions on how test classes should be implemented, and it's not possible to inject bean way you want.

ps. From Spring 4.3 you no need @Autowired:

@Service
class AccountTest(val ap: AccountProcessor) {