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

如何在同一测试类中Mock Bean部分方法,其余用原Bean实现?

问题分析与解决方案

你的问题核心在于Spring容器中的Bean引用不一致:你在TestAppConfiguration里手动通过new PersonServiceImpl(personDao())创建了Service实例,这个Service持有的是直接调用personDao()得到的TestPersonDaoImpl实例;而你用@MockBean声明的PersonDao是Spring容器管理的另一个独立实例,Service根本没用到它,所以你的mock操作自然不会生效。

解决步骤

1. 修改TestConfiguration,让Spring管理DAO的依赖注入

首先要让Service通过Spring的依赖注入获取DAO,而不是手动传入实例。这样Spring才能保证Service使用的是容器中当前生效的DAO Bean(不管是Test实现还是mock/spy实例):

@TestConfiguration
public class TestAppConfiguration {
    @Bean
    public PersonService personService(PersonDao personDao) {
        // 改为通过参数注入PersonDao,而非手动调用personDao()创建实例
        return new PersonServiceImpl(personDao);
    }

    @Bean
    @Primary // 标记为默认实现,当容器中有多个PersonDao时优先使用
    public PersonDao personDao() {
        return new TestPersonDaoImpl();
    }
}

2. 使用@SpyBean替代@MockBean实现按需mock

因为你希望95%的场景使用TestPersonDaoImpl的真实逻辑,只在少数测试中覆盖特定方法,@SpyBean是最佳选择:它会包装容器中已有的TestPersonDaoImpl实例,默认行为完全遵循原实现,只有你明确存根的方法才会被mock。

修改测试类:

@RunWith(SpringRunner.class)
@Import(TestAppConfiguration.class)
public class PersonServiceTests {
    @Autowired
    private PersonService personService;

    @SpyBean // 包装容器中的TestPersonDaoImpl实例
    private PersonDao personDao;

    // 可选:测试后重置Spy,避免不同测试间的状态影响
    @After
    public void tearDown() {
        Mockito.reset(personDao);
    }

    @Test
    public void getAllPersons() {
        assertThat(personService.getAllPersons().size()).isGreaterThan(0);
    }

    @Test
    public void getPersonById() {
        assertThat(personService.getPersonById(1L).getName()).isEqualTo("Susan");
    }

    @Test
    public void getAllPersons_NoPersons(){
        // 存根findAll方法,返回空列表
        doReturn(new ArrayList<>()).when(personDao).findAll();
        
        // 验证结果符合预期
        assertThat(personService.getAllPersons().size()).isEqualTo(0);
        
        // 可选:验证DAO方法确实被Service调用
        verify(personDao).findAll();
    }
}

为什么之前的方法不生效?

  • 你用@MockBean声明的PersonDao是Spring创建的全新mock实例,但你的Service持有的是TestAppConfiguration中手动创建的TestPersonDaoImpl实例,两者没有任何关联。
  • 即使你用@Spy注解,如果Service没有使用容器中的DAO实例,Spy也无法作用到Service持有的DAO对象上。

额外小提示

你的TestPersonDaoImpl中的findById方法签名有错误:public List<PersonModel> findById(id)应该改为public PersonModel findById(Long id)(或者和Service中的调用逻辑匹配),否则会出现编译报错哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:17:23