使用@WebMvcTest配合@Import失效,测试上下文要求@Repository Bean
问题根源
@WebMvcTest是专门针对**Web层(控制器)**的轻量级测试注解,默认只会加载控制器、Spring MVC相关配置,不会初始化JPA、Repository这类持久层组件。你直接@Import(CraftService::class)后,Spring会尝试创建CraftService实例,但它依赖的itemRepository、playerRepository属于持久层Bean,在@WebMvcTest的环境里没有被初始化(缺少entityManagerFactory就是这个原因),所以抛出异常。
解决方案
方案1:用@MockBean模拟Service的依赖(推荐)
既然是测试Web层,不需要真实的Repository实现,直接用Mock模拟CraftService依赖的所有Repository,让Spring能正常创建CraftService:
@WebMvcTest(CraftController::class) // 明确指定要测试的控制器 class CraftApiTest { @Autowired private lateinit var mockMvc: MockMvc @MockBean private lateinit var itemRepository: ItemRepository // 模拟Repository @MockBean private lateinit var playerRepository: PlayerRepository // 模拟另一个Repository @Autowired private lateinit var craftService: CraftService // 此时Service能被正常注入,依赖都是Mock // 测试方法... }
这样Spring会用Mock实例替代真实的Repository,不需要加载JPA环境,完美适配@WebMvcTest的轻量级特性。
方案2:改用@SpringBootTest + @AutoConfigureMockMvc
如果你的测试需要真实的Service和Repository(比如要做完整的集成测试),那就放弃@WebMvcTest,用@SpringBootTest启动完整的Spring上下文,再配合@AutoConfigureMockMvc来测试API:
@SpringBootTest @AutoConfigureMockMvc class CraftApiTest { @Autowired private lateinit var mockMvc: MockMvc // 测试方法... }
这种方式会加载整个应用上下文,包括JPA、Repository等组件,适合需要真实数据交互的集成测试。
方案3:自定义测试配置,排除Repository自动配置
如果一定要用@WebMvcTest且不想用Mock,也可以通过@TestConfiguration手动配置Service,同时排除JPA相关的自动配置:
@WebMvcTest(CraftController::class) @Import(CraftApiTest.TestConfig::class) class CraftApiTest { @Autowired private lateinit var mockMvc: MockMvc @TestConfiguration class TestConfig { // 手动创建CraftService,注入Mock的Repository或者自定义的Stub实现 @Bean fun craftService(): CraftService { return CraftService(Mockito.mock(ItemRepository::class.java), Mockito.mock(PlayerRepository::class.java)) } } // 测试方法... }
不过这种写法不如方案1简洁,一般不推荐。
总结
- 纯Web层测试:用
@WebMvcTest+@MockBean模拟Service的依赖,这是@WebMvcTest的设计初衷。 - 完整集成测试:用
@SpringBootTest+@AutoConfigureMockMvc。
内容的提问来源于stack exchange,提问作者xetra11

