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

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

相关产品推荐
方舟 Agent Plan

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

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