Home

Awesome

SpringMockK

CircleCI

Support for Spring Boot integration tests written in Kotlin using MockK instead of Mockito.

Spring Boot provides @MockBean and @SpyBean annotations for integration tests, which create mock/spy beans using Mockito.

This project provides equivalent annotations MockkBean and SpykBean to do the exact same thing with MockK.

Principle

All the Mockito-specific classes of the spring-boot-test library, including the automated tests, have been cloned, translated to Kotlin, and adapted to MockK.

This library thus provides the same functionality as the standard Mockito-based Spring Boot mock beans.

For example (using JUnit 5, but you can of course also use JUnit 4):

@ExtendWith(SpringExtension::class)
@WebMvcTest
class GreetingControllerTest {
    @MockkBean
    private lateinit var greetingService: GreetingService
    
    @Autowired
    private lateinit var controller: GreetingController
    
    @Test
    fun `should greet by delegating to the greeting service`() {
        every { greetingService.greet("John") } returns "Hi John"
        
        assertThat(controller.greet("John")).isEqualTo("Hi John")
        verify { greetingService.greet("John") }
    }
}

Usage

Gradle (Kotlin DSL)

Add this to your dependencies:

testImplementation("com.ninja-squad:springmockk:4.0.2")

If you want to make sure Mockito (and the standard MockBean and SpyBean annotations) is not used, you can also exclude the mockito dependency:

testImplementation("org.springframework.boot:spring-boot-starter-test") {
    exclude(module = "mockito-core")
}

Maven

Add this to your dependencies:

<dependency>
  <groupId>com.ninja-squad</groupId>
  <artifactId>springmockk</artifactId>
  <version>4.0.2</version>
  <scope>test</scope>
</dependency>

Differences with Mockito

Gotchas

In some situations, the beans that need to be spied are JDK proxies. In recent versions of Java (Java 16+ AFAIK), MockK can't spy JDK proxies unless you pass the argument --add-opens java.base/java.lang.reflect=ALL-UNNAMED to the JVM running the tests.

Not doing that and trying to spy on a JDK proxy will lead to an error such as

java.lang.IllegalAccessException: class io.mockk.impl.InternalPlatform cannot access a member of class java.lang.reflect.Proxy (in module java.base) with modifiers "protected"

To pass that option to the test JVM with Gradle, configure the test task with

tasks.test {
    // ...
    jvmArgs(
        "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED"
    )
}

For Maven users:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
      <argLine>
        --add-opens java.base/java.lang.reflect=ALL-UNNAMED
      </argLine>
    </configuration>
</plugin>

Limitations

Versions compatibility

How to build

  ./gradlew build