SpringMockK Documentation

repository·master·Indexed 19 days ago

https://github.com/ninja-squad/springmockk

SpringMockK provides support for Spring Boot integration tests written in Kotlin by using MockK instead of Mockito. It offers Kotlin-friendly alternatives to Spring's Mockito-based annotations, such as @MockkBean and @MockkSpyBean, to create mock and spy beans within the Spring ApplicationContext.

Tokens
1.1K
Snippets
3
Records
6
Agent score
18%

What's inside SpringMockK

  1. Configure Qualifier annotations for @MockkBean

    master

    When using custom qualifier annotations with @MockkBean, ensure the annotation targets fields rather than properties. If your annotation targets properties, use the @field: site-target prefix to ensure it is applied correctly to the bean:

    @MockkBean
    @field:YourQualifier
    private lateinit var myService: MyService
  2. Stubbing beans wrapped in Spring AOP proxies

    master
    When spying on a bean that is wrapped in a Spring AOP proxy (e.g., due to @Cacheable), you cannot stub or verify the bean directly. You must target the underlying object. Use AopTestUtils.getUltimateTargetObject() to retrieve the actual target for stubbing and verification.
  3. Use @MockkBean and @MockkSpyBean for Spring integration tests

    master

    SpringMockK provides Kotlin-friendly alternatives to Spring's Mockito annotations. Use @MockkBean to create a mock bean and @MockkSpyBean to create a spy bean within the Spring ApplicationContext.

    Mocking Behavior

    By default, mocks created with these annotations are strict (not relaxed). You can configure them using:

    • @MockkBean(relaxed = true)
    • @MockkBean(relaxUnitFun = true)

    Example Usage

    @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") }
        }
    }
  4. Migrate to SpringMockK 5.x

    master

    If upgrading from version 4.x or earlier to 5.x, apply the following changes to align with the Spring Framework's native Mockito support:

    • Rename Annotation: Replace @SpykBean with @MockkSpyBean.
    • Repeatable Annotations: @MockkBean and @MockkSpyBean are now natively repeatable in Kotlin. Do not use @MockkBeans or @SpykBeans; instead, repeat the individual annotations.
    • Rename classes to types: Change @MockkBean(classes = [SomeService::class]) to @MockkBean(types = [SomeService::class]).
    • Rename value to name: The value property is now an alias for name. If you were using @MockkBean([SomeService::class]), rewrite it as @MockkBean(types = [SomeService::class]).
    • Rename Extension Property: com.ninjasquad.springmockk.MockkFunctionsKt.isMock is now isMockOrSpy.
  5. Install SpringMockK via Gradle or Maven

    master

    To use SpringMockK in your Kotlin Spring Boot integration tests, add the dependency to your build configuration.

    Gradle (Kotlin DSL)

    Add the following to your dependencies block:

    Maven

    Add the following to your dependencies block:

    Note: Ensure you use the version compatible with your Spring/Java environment.

    // Gradle (Kotlin DSL)
    testImplementation("com.ninja-squad:springmockk:5.0.1")
    
    <!-- Maven -->
    <dependency>
      <groupId>com.ninja-squad</groupId>
      <artifactId>springmockk</artifactId>
      <version>5.0.1</version>
      <scope>test</scope>
    </dependency>```
  6. Handle JDK proxy issues when spying with MockK

    master

    In Java 16+, MockK may fail to spy on JDK proxies, resulting in an java.lang.IllegalAccessException. To resolve this, you must pass the --add-opens java.base/java.lang.reflect=ALL-UNNAMED argument to the JVM running your tests.

    Gradle Configuration

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

    Maven Configuration

    <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>