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

Spring Mockito测试问题:saveAndFlush()未写入Mock仓库

解决Mockito Mock仓库调用saveAndFlush()后无数据的问题

嗨,我来帮你捋清楚问题出在哪~

首先要明白:你用@Mock创建的AccountRepository是一个模拟对象,它本质上是个“假”仓库——Mockito的Mock对象所有方法默认都是空实现,要么返回null、要么返回空集合这类默认值。你直接调用repo.saveAndFlush(account)根本不会真的把数据存进去,因为这个方法的默认逻辑啥也没做。

再看你的测试方法list(),这里还有个逻辑倒置的问题:你写了when(underTest.list()).thenReturn(mockList),相当于直接给Controller的list()方法硬编码了返回值,完全跳过了list()方法内部调用repo.findAll()的真实逻辑。而mockList是repo.findAll()的结果(Mock默认返回空列表),所以你断言size() == 0自然会通过,但这根本没测试到Controller的真实行为。

修复方案&优化后的代码

我们调整测试逻辑,让它真正验证Controller的行为:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class) // 替代手动初始化Mock,JUnit5标准用法
public class AccountTest { 
    @InjectMocks 
    private AccountController underTest; 
    @Mock 
    private AccountRepository repo; 
    private Account account; 

    @BeforeEach 
    void setUp() { 
        // 初始化测试用的Account对象
        account = new Account();
        account.setAccountNumber(6666L); 
        account.setName("Steph"); 
    } 

    @Test 
    void list_ShouldReturnAllAccounts() { 
        // 告诉Mock仓库:当调用findAll()时,返回包含测试账户的列表
        when(repo.findAll()).thenReturn(List.of(account));

        // 真正调用Controller的list方法,获取返回结果
        List<Account> result = underTest.list();

        // 断言结果符合预期
        assertEquals(1, result.size());
        assertEquals("Steph", result.get(0).getName());
    }

    // 额外加一个测试save逻辑的方法(如果你的Controller有save接口)
    @Test
    void save_ShouldCallRepositorySave() {
        // 调用Controller的save方法
        underTest.save(account);

        // 验证Mock仓库的saveAndFlush方法确实被调用了一次,参数是我们的测试账户
        verify(repo).saveAndFlush(account);
    }
}

关键知识点总结

  • @Mock对象不会执行真实逻辑,必须用when(...).thenReturn(...)指定方法返回值,或者用verify()验证方法是否被调用。
  • @InjectMocks会自动把Mock对象注入到被测试类(这里是AccountController),确保Controller调用的是我们的模拟仓库。
  • 测试的核心是调用被测试类的方法,然后断言返回结果,而不是直接给被测试方法硬设返回值——后者完全失去了测试的意义。
  • 用@ExtendWith(MockitoExtension.class)替代MockitoAnnotations.initMocks(this),是JUnit 5更简洁、规范的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 13:22:27