SpringBoot服务JUnit5 Mockito测试中如何调用JPA Repository真实方法
问题原因
你遇到的报错根本原因是:InventoryRepository是继承JpaRepository的接口,你定义的findByInventoryIdAndCompanyId是抽象方法,本身没有实现逻辑。Spring Data JPA会在项目启动时动态生成该接口的实现类,而你用Mockito的@Mock生成的代理对象没有对应的实现逻辑,thenCallRealMethod要求被调用的方法必须是有实际实现的非抽象方法,所以直接抛出异常。
可行解决方案
方案1:使用Spring Boot集成测试注入真实Repository(推荐要真实查库的场景)
如果需要调用Repository的真实方法查询实际数据库,直接放弃使用Mockito Mock Repository,改用Spring测试框架注入真实的Bean即可:
- 测试类加上
@SpringBootTest注解启动Spring上下文 - 用
@Autowired注入InventoryService和InventoryRepository,移除@Mock、@InjectMocks注解
示例代码:
@SpringBootTest class InventoryServiceTest { @Autowired private InventoryService inventoryService; @Test public void getInventoryByIdTest() { Assertions.assertEquals(16591,inventoryService.getInventoryById(16591 , 1).getInventoryId()); } }
方案2:用H2内存数据库做轻量集成测试(避免污染正式库)
如果不想连接实际的业务数据库,可以引入H2内存数据库作为测试专用数据源,Spring会自动生成Repository的实现类操作内存库,数据会在测试结束后自动清除:
- pom/gradle引入H2依赖
<!-- Maven 依赖 --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency>
- test/resources下新增application-test.yml配置:
spring: datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:testdb username: sa password: jpa: hibernate: ddl-auto: update show-sql: true
- 测试类用法和方案1一致,测试前可以通过
@Sql注解或者JPA接口预先插入测试数据。
方案3:纯单元测试场景直接Mock返回值
如果只是验证服务层的逻辑正确性,不需要真实查询数据库,推荐直接Mock Repository的返回值,不需要调用真实方法:
@Test public void getInventoryByIdTest() { // 构造模拟的返回对象 Inventory mockInventory = new Inventory(); mockInventory.setInventoryId(16591); // 替换thenCallRealMethod为thenReturn自定义的模拟对象 when(inventoryRepository.findByInventoryIdAndCompanyId(16591,1)).thenReturn(mockInventory); Assertions.assertEquals(16591,inventoryService.getInventoryById(16591 , 1).getInventoryId()); }
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

