Kotlintest与WebMvcTest整合疑问:@WithMockUser注解无法使用?
Absolutely! KotlinTest plays nicely with Spring's @WebMvcTest—the issue you're seeing with @WithMockUser is just a matter of adapting Spring Security's annotation-based approach to KotlinTest's function-driven test style. Let's break down how to make this work.
Why @WithMockUser Doesn't Work Directly on KotlinTest Test Functions
KotlinTest uses its own test lifecycle and defines tests as regular functions (e.g., fun myMvcTest()) instead of relying on JUnit's @Test annotation. Spring's @WithMockUser is tied to JUnit's test execution model, so applying it directly to a KotlinTest test function won't trigger the security context setup you need.
Working Solutions to Add Mock Authentication
Here are two straightforward ways to get @WithMockUser-like behavior in your KotlinTest + @WebMvcTest setup:
1. Use Spring Security's withMockUser Static Function in Test Blocks
The simplest approach is to wrap your MVC test logic in Spring Security's withMockUser utility function. This explicitly sets up the security context for the duration of the block:
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.withMockUser import io.kotest.core.spec.style.BehaviorSpec import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.get @WebMvcTest(YourController::class) class YourControllerTest( private val mockMvc: MockMvc ) : BehaviorSpec({ given("a secured endpoint") { `when`("an authenticated user makes a request") { then("it should return 200 OK") { withMockUser(username = "testUser", roles = ["USER"]) { mockMvc.get("/secured") .andExpect { status { isOk() } } } } } } })
2. Create a Custom KotlinTest TestListener for Global Authentication
If you want to apply mock user authentication to all tests in a class (instead of repeating the wrapper), you can create a TestListener that sets up the security context before each test:
import io.kotest.core.listeners.TestListener import io.kotest.core.test.TestCase import io.kotest.core.test.TestResult import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.context.SecurityContextHolder class MockUserListener( private val username: String = "testUser", private val roles: Array<String> = arrayOf("USER") ) : TestListener { override suspend fun beforeTest(testCase: TestCase) { val authorities = roles.map { org.springframework.security.core.authority.SimpleGrantedAuthority("ROLE_$it") } val authToken = UsernamePasswordAuthenticationToken(username, null, authorities) SecurityContextHolder.getContext().authentication = authToken } override suspend fun afterTest(testCase: TestCase, result: TestResult) { SecurityContextHolder.clearContext() } } // Use the listener in your test class: @WebMvcTest(YourController::class) class YourControllerTest( private val mockMvc: MockMvc ) : BehaviorSpec({ listener(MockUserListener()) given("a secured endpoint") { `when`("a request is made") { then("it should return 200 OK") { mockMvc.get("/secured") .andExpect { status { isOk() } } } } } })
Key Dependencies to Verify
Make sure you have these dependencies in your build file to ensure smooth compatibility:
io.kotest:kotest-extensions-spring: Integrates KotlinTest with Spring's test contextorg.springframework.security:spring-security-test: Provides thewithMockUserutility and security testing utilities
Final Verdict
Your request is totally feasible! KotlinTest's flexible, expressive syntax pairs great with Spring's MVC testing tools—you just need to adjust how you handle security context setup to fit KotlinTest's model instead of JUnit's.
内容的提问来源于stack exchange,提问作者RomainZ

