Java Spring新手基于Mock CrudRepository实现CustomerRepository求建议
实现合理性评估
当前给出的CustomerRepository实现不符合Mock CrudRepository的核心需求,还存在多个可直接导致运行异常或逻辑错误的问题:
- 内部依赖的
CrudRepository crudrepository成员没有初始化,运行时调用任意方法都会直接抛出NullPointerException - 成员变量使用了裸类型的
CrudRepository,没有声明泛型参数,存在类型安全风险,代码中多处不必要的强制类型转换也源于此 deleteAllById方法实现错误:你在方法内调用的是crudrepository.deleteAll(entities),而非对应接口要求的deleteAllById,逻辑完全不符- 完全没有Mock的作用:当前类本质是CrudRepository的静态代理壳,没有自己的模拟存储逻辑,还依赖其他CrudRepository实现,完全达不到Mock的目的
save方法返回值不符合接口规范:Spring的CrudRepository的save方法返回的是持久化后的实例(可能携带自动生成的主键、填充的审计字段等,和入参实例不一定是同一个对象),你直接返回入参entity的写法不符合接口约定
优化建议
分两种场景给你对应的优化方案:
场景1:需要自己手动实现Mock版的CustomerRepository
直接移除内部的CrudRepository依赖,用内存集合模拟存储即可,示例实现如下:
import java.util.HashMap; import java.util.Map; import java.util.Optional; public class MockCustomerRepository implements CrudRepository<Customer, String> { // 用HashMap作为模拟存储 private final Map<String, Customer> storage = new HashMap<>(); @Override public long count() { return storage.size(); } @Override public <S extends Customer> S save(S entity) { // 这里假设Customer的getId()方法可以拿到主键 storage.put(entity.getId(), entity); return entity; // 如果要贴合真实CrudRepository的行为,可以在这里复制对象后返回副本 } @Override public <S extends Customer> Iterable<S> saveAll(Iterable<S> entities) { entities.forEach(this::save); return entities; } @Override public Optional<Customer> findById(String id) { return Optional.ofNullable(storage.get(id)); } @Override public Iterable<Customer> findAllById(Iterable<String> ids) { return ids.stream() .map(storage::get) .filter(java.util.Objects::nonNull) .toList(); } @Override public Iterable<Customer> findAll() { return storage.values(); } @Override public boolean existsById(String id) { return storage.containsKey(id); } @Override public void deleteById(String id) { storage.remove(id); } @Override public void delete(Customer entity) { storage.remove(entity.getId()); } @Override public void deleteAllById(Iterable<? extends String> ids) { ids.forEach(storage::remove); } @Override public void deleteAll() { storage.clear(); } @Override public void deleteAll(Iterable<? extends Customer> entities) { entities.forEach(this::delete); } }
场景2:单元测试场景需要Mock CrudRepository
不需要自己写实现类,直接用Mockito等测试框架直接Mock接口即可,示例用法:
// 导入Mockito的相关类后直接 mock 接口 CrudRepository<Customer, String> mockRepo = Mockito.mock(CrudRepository.class); // 自定义mock方法的返回值 Mockito.when(mockRepo.findById("123")).thenReturn(Optional.of(new Customer("123", "张三")));
补充说明
如果你是正常使用Spring Data JPA的场景,不需要手动实现CrudRepository,只需要声明接口即可,Spring会自动生成实现类:
public interface CustomerRepository extends CrudRepository<Customer, String> { // 直接在这里加自定义查询方法即可,不需要写实现 }
内容的提问来源于stack exchange,提问作者tionRegist
相关产品推荐
相关产品推荐

