Run unit tests with spring boot, "no runnable methods" error

Viewed 1932

I'm running unit tests with Spring boot, but I get a weird no runnable error. The tests pass by the way, but after all test have ended successfully, I get this weird error out of nowhere:

java.lang.Exception: No runnable methods

at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:191)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:137)
at org.springframework.test.context.junit4.SpringRunner.<init>(SpringRunner.java:49)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)

How do I fix this? Why is Spring boot looking for a runnable in my tests?

Here is an example of my code

package ca.bell.uc.hello.world

import org.junit.Assert
import org.junit.jupiter.api.Test
import org.junit.runner.RunWith
import org.springframework.test.context.junit4.SpringRunner


@RunWith(SpringRunner::class)
internal class example {

    @Test
    fun f() {
        Assert.assertTrue(true)
    }
}

And here is a screenshot of the error:

enter image description here

Thanks

P.S. This is Kotlin

2 Answers

You are trying to use JUnit 5 @Test annotation because of import:

import org.junit.jupiter.api.Test

In the console log we can see that JUnit 4 is used.

If you want to work with JUnit 4 you should use the import:

import org.junit.Test

Indeed it's the mix of JUnit4 and JUnit5. I had the same thing with tests with @Ignore or @Disabled that would not want to get ignored based on which @Test it was.

You can avoid this issue with spring by updating your spring dependencies and remove the Junit4 dependencies from your build.gradle.kts so that you won't mix them (tested with Gradle v6, check the groovy syntax if you use build.gradle).

  testImplementation("org.springframework.boot:spring-boot-starter-test") {
    exclude(module = "junit")
    exclude(module = "junit-vintage-engine")
    exclude(module = "mockito-core")
  }
  testImplementation("org.junit.jupiter:junit-jupiter:5.4.2")
  testImplementation("org.junit.jupiter:junit-jupiter-api")
  testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")

Once you have that you don't need to use @RunWith(SpringRunner::class) you can see the difference in your import, they should all contains "jupiter" and your class could look like this:

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

internal class ExampleTest {

  @Test
  fun test() {
    Assertions.assertTrue(true)
  }
}
Related