如何在同一测试类中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
相关产品推荐
相关产品推荐

