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

使用Mockito测试数据库数据存储时遭遇NotAMockException错误求助

问题分析与解决

错误原因

你碰到的NotAMockException是因为**workerService不是Mockito生成的mock对象**,却使用了Mockito.doReturn().when(workerService)这种仅适用于mock对象的语法。同时你的测试逻辑顺序也有误——应该先配置mock行为,再调用目标方法,最后做验证和断言。

修正方案

根据你的需求,分两种场景给出解决方案:

场景1:纯单元测试(Mock Repository,不操作真实数据库)

这种场景下我们mock数据访问层(WorkerRepository),只验证服务层是否正确调用了repository的方法,同时模拟查询结果做断言:

@ExtendWith(MockitoExtension.class)
class WorkerServiceTest {

    // 用@Mock标记需要mock的依赖
    @Mock
    private WorkerRepository workerRepository;

    // 用@InjectMocks将mock的repository注入到service中
    @InjectMocks
    private WorkerService workerService;

    @Test
    void workerShouldBeSavedCorrectly() {
        // 1. 准备测试数据
        Worker worker = new Worker("Name", "reqwrqwe321412");

        // 2. 配置mock:当调用repository的findByName方法时,返回我们准备的worker
        Mockito.when(workerRepository.findByName(worker.getName())).thenReturn(worker);

        // 3. 调用被测试的服务方法
        workerService.create(worker);

        // 4. 验证repository的save方法被调用了1次,且参数正确
        Mockito.verify(workerRepository, Mockito.times(1)).save(worker);

        // 5. 断言查询结果与原对象一致
        Worker foundWorker = workerRepository.findByName(worker.getName());
        Assertions.assertEquals(worker, foundWorker);
    }
}

场景2:集成测试(操作真实测试数据库)

如果你的核心需求是验证数据真的被保存到数据库并能正确查询,这属于集成测试范畴,不需要mock repository,而是使用内存数据库(如H2)配合Spring容器做真实操作:

@SpringBootTest
@Transactional // 测试结束后自动回滚数据,避免污染测试环境
class WorkerServiceIntegrationTest {

    @Autowired
    private WorkerService workerService;

    @Autowired
    private WorkerRepository workerRepository;

    @Test
    void workerShouldBeSavedToDatabaseCorrectly() {
        // 1. 准备测试数据
        Worker worker = new Worker("Name", "reqwrqwe321412");

        // 2. 调用服务方法保存数据到数据库
        workerService.create(worker);

        // 3. 从真实数据库查询数据
        Worker foundWorker = workerRepository.findByName(worker.getName());

        // 4. 断言查询结果的属性与原对象一致
        Assertions.assertNotNull(foundWorker);
        Assertions.assertEquals(worker.getName(), foundWorker.getName());
        Assertions.assertEquals(worker.getPassword(), foundWorker.getPassword()); // 替换为你的实体字段

        // 如果一定要验证save方法的调用次数,可以用spy包装真实的repository
        // WorkerRepository spyRepo = Mockito.spy(workerRepository);
        // workerService.setWorkerRepository(spyRepo); // 需要service提供setter方法
        // spyRepo.save(worker);
        // Mockito.verify(spyRepo, Mockito.times(1)).save(worker);
    }
}

关键注意点

  • 单元测试中,只有被@Mock标记的对象才能使用Mockito的when()/doReturn()等语法,非mock对象调用这些方法会抛出NotAMockException。
  • 测试逻辑必须遵循「准备数据 → 配置mock → 调用方法 → 验证交互 → 断言结果」的顺序。
  • 集成测试依赖Spring容器注入真实Bean,@Transactional注解可以保证每次测试后数据回滚,避免测试数据互相干扰。

内容的提问来源于stack exchange,提问作者ZabbixJs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:33:13