You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin+Mockk环境下如何Mock SpringBoot Repository避免测试操作真实数据库

问题原因

你在测试类中手动构造的standingOrderRepository、standingOrderServiceImpl等Mock实例,没有被纳入Spring的测试上下文管理。Spring容器运行时仍然使用自动扫描创建的真实实现类,所以不管是MockMvc发起的请求,还是直接调用上下文内的Bean方法,都会触发真实数据库的读写操作。

解决方案

分为两种常用测试场景适配:

场景1:保留@SpringBootTest集成测试,使用MockMvc测试接口

这是你当前的测试写法,只需要替换Mock的注入方式即可:

  1. 首先引入SpringMockk依赖,实现Mockk和Spring Boot测试体系的适配
    Gradle依赖:
testImplementation "com.ninja-squad:springmockk:4.0.2"

Maven依赖:

<dependency>
    <groupId>com.ninja-squad</groupId>
    <artifactId>springmockk</artifactId>
    <version>4.0.2</version>
    <scope>test</scope>
</dependency>
  1. 修改测试类代码,用@MockkBean注解替换手动Mock的Bean,Spring会自动将上下文内的对应Bean替换为Mock实例,不需要你手动构造Controller
    修改后的测试类示例:
@SpringBootTest
@AutoConfigureMockMvc
internal class StandingOrderResourceTest {

    @Autowired
    lateinit var mockMvc: MockMvc
    @Autowired
    lateinit var objectMapper: ObjectMapper

    // 用@MockkBean替换手动mock,自动注入到Spring上下文
    @MockkBean
    lateinit var standingOrderMapper: StandingOrderMapper
    @MockkBean
    lateinit var standingOrderRepository: StandingOrderRepository
    @MockkBean
    lateinit var standingOrderServiceImpl: StandingOrderServiceImpl

    val baseUrl = "/api"

    @Nested
    @DisplayName("GetStandingOrders()")
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    inner class GetStandingOrders {
        @Test
        fun `should return all StandingOrders`() {
            // 先给Mock方法定义Stub返回规则
            val testStandingOrders = listOf(StandingOrder()) // 构造你的测试实体
            val testDtoList = listOf(StandingOrderDto()) // 构造你的测试返回DTO
            every { standingOrderRepository.findAll() } returns testStandingOrders
            every { standingOrderServiceImpl.getStandingOrders() } returns testDtoList

            mockMvc.get(baseUrl)
                .andDo { print() }
                .andExpect {
                    status { isOk() }
                    content { contentType(MediaType.APPLICATION_JSON)}
                    // 可以补充返回内容校验
                    jsonPath("$[0].id") { value(testDtoList[0].id) }
                }
        }
    }
}

场景2:纯单元测试,不需要启动Spring容器(执行速度更快)

如果只需要测试Controller的逻辑,不需要测试Spring框架相关的拦截器、参数绑定等能力,可以直接走纯单元测试:

internal class StandingOrderResourceTest {

    private val standingOrderMapper = mockk<StandingOrderMapper>()
    private val standingOrderRepository = mockk<StandingOrderRepository>()
    private val standingOrderServiceImpl = mockk<StandingOrderServiceImpl>()
    // 手动构造Controller,注入Mock的Service
    private val standingOrderResource = StandingOrderResource(standingOrderServiceImpl)

    @Test
    fun `should return all StandingOrders`() {
        val testDtoList = listOf(StandingOrderDto())
        every { standingOrderServiceImpl.getStandingOrders() } returns testDtoList

        val result = standingOrderResource.getStandingOrders()
        assertEquals(testDtoList, result)
    }
}
注意事项
  • 不要混用手动构造实例和Spring自动注入实例,两种测试模式二选一:要么完全不启动Spring容器手动构造所有依赖做单元测试,要么全交给Spring上下文管理,用@MockkBean替换需要Mock的Bean
  • 所有Mock对象的被调用方法必须提前定义Stub规则,否则Mockk会抛出MissingStubInvocationException异常

内容的提问来源于stack exchange,提问作者X5H4Kocur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:24:00