Spring是否提供JpaRepositories存根实现?如何无Mockito单元测试Service类
不用Mockito测试Spring JPA Service类的可行方案
刚好我之前也处理过类似的需求,给你几个不用Mockito就能测试SomeQueryService这类依赖JPA Repository的Service的方案,顺便解答你关于Spring是否提供JpaRepository存根实现的疑问:
首先明确一点:Spring本身并没有对外提供官方的JpaRepository存根实现,但我们有几种替代方案可以绕开Mockito完成测试,每种方案适用于不同的场景:
1. 用内存数据库跑真实的Repository实现(最贴近生产环境)
这是最常用的方案,我们可以借助H2内存数据库,让Spring Data自动生成真实的JpaRepository代理类,完全不用模拟依赖。这种方式测试的是真实的业务逻辑和JPA交互,结果可信度最高。
步骤:
- 首先在你的测试依赖中加入H2数据库(Maven/Gradle都可以)
- 在测试资源目录下配置
application-test.properties,指定H2内存库:spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop - 编写测试类,用
@DataJpaTest(轻量,只加载JPA相关上下文)加上@Import导入你的Service类:
@DataJpaTest @Import(SomeQueryService.class) // @DataJpaTest默认只扫描Repository,所以手动导入Service class SomeQueryServiceTest { @Autowired private SomeRepository repository; @Autowired private SomeQueryService service; @Test void doSomething_ShouldExecuteCorrectly() { // 1. 准备测试数据 repository.save(new SomeEntity("test-data")); // 2. 调用Service的目标方法 service.doSomething(); // 3. 验证结果,直接查询Repository看数据是否符合预期 List<SomeEntity> result = repository.findAll(); assertThat(result).hasSize(1); assertThat(result.get(0).getName()).isEqualTo("test-data"); // 根据你的业务逻辑添加更多断言 } }
2. 手动实现存根版Repository(纯单元测试,速度最快)
如果你的测试不需要验证JPA的具体行为,只需要测试Service本身的逻辑,可以手动写一个SomeRepository的存根实现,用内存集合模拟数据操作:
存根实现:
public class StubSomeRepository implements SomeRepository { private final List<SomeEntity> inMemoryData = new ArrayList<>(); @Override public <S extends SomeEntity> S save(S entity) { inMemoryData.add(entity); return entity; } @Override public List<SomeEntity> findAll() { // 返回副本,避免外部修改内部数据 return new ArrayList<>(inMemoryData); } // 实现Service中用到的其他Repository方法,比如findById、delete等 }
测试类:
class SomeQueryServiceTest { // 直接实例化存根和Service,不需要Spring上下文 private final SomeRepository stubRepo = new StubSomeRepository(); private final SomeQueryService service = new SomeQueryService(stubRepo); @Test void doSomething_ShouldManipulateDataAsExpected() { service.doSomething(); // 验证存根中的数据变化是否符合预期 assertThat(stubRepo.findAll()).hasSize(1); } }
这种方式完全脱离Spring容器,是纯Java单元测试,执行速度极快,适合测试Service的核心业务逻辑。
3. 用Spring Data内部的StubRepositoryFactoryBean(快速生成简单存根)
Spring Data内部有一个StubRepositoryFactoryBean类,它可以自动生成Repository的存根实现,默认会为所有方法返回合理的默认值(比如findAll返回空列表,save返回传入的实体)。不过这个类是Spring Data内部测试用的,没有正式对外文档,版本兼容性需要注意。
配置存根Bean:
@Configuration class StubRepositoryConfig { @Bean public StubRepositoryFactoryBean<? extends SomeRepository, SomeEntity, Long> someRepository() { return new StubRepositoryFactoryBean<>(SomeRepository.class); } }
测试类:
@SpringBootTest(classes = {StubRepositoryConfig.class, SomeQueryService.class}) class SomeQueryServiceTest { @Autowired private SomeRepository repository; @Autowired private SomeQueryService service; @Test void doSomething_ShouldInteractWithRepository() { service.doSomething(); // 根据存根的默认行为做断言,比如findAll返回空列表(如果你的Service没有保存数据的话) assertThat(repository.findAll()).isEmpty(); } }
这个方案适合快速生成简单存根,但定制性不如手动写的存根,如果需要复杂的行为,还是推荐手动实现。
内容的提问来源于stack exchange,提问作者Tomasz Bawor
相关产品推荐
相关产品推荐

