何时应使用@MockBean而非@Mock?相关技术疑问解析
已明确的基础信息
@Mock和手动调用mock()方法的作用一致,都是用来创建Mock对象@MockBean是基于@Mock的封装,核心能力是把创建的Mock对象注册到Spring应用上下文当中@MockBean最常出现在标注了@WebMvcTest的控制器测试用例里
疑问解答
1. 什么时候该用@MockBean而不是@Mock?
分场景判断:
- 写不加载Spring上下文的普通单元测试时,直接用
@Mock即可,不需要和Spring容器交互 - 但如果是需要Spring上下文的测试(比如用
@WebMvcTest、@SpringBootTest这类注解的测试),且要Mock的对象是Spring容器管理的Bean(比如控制器依赖的Service、Repository),就必须用@MockBean——它会把Mock对象替换掉上下文里原本的真实Bean,让依赖它的其他Spring Bean能正常注入这个Mock实例。
2. 为什么要把Mock对象加到上下文里?是为了复用提升效率吗?
完全不是为了复用提效率,核心目的是让Spring上下文里的其他Bean能拿到这个Mock对象。举个例子:测试控制器时,控制器是Spring管理的Bean,它依赖的Service也是Spring Bean。如果用普通@Mock创建Service的Mock对象,Spring根本不知道这个对象存在,控制器还是会尝试注入真实的Service实例,要么报错(比如Service依赖的资源没初始化),要么测试用到真实逻辑,达不到Mock隔离的效果。把Mock对象放进上下文,Spring才能把它注入给控制器,让测试环境的依赖完全可控。
3. 在控制器测试里用@Mock代替@MockBean会怎么样?
在@WebMvcTest的控制器测试中,用@Mock替代@MockBean的话,这个Mock对象不会被注册到Spring上下文。此时控制器依赖的Bean(比如Service)会出现两种情况:要么Spring找不到对应的Bean实例,直接抛出依赖注入失败的异常;要么Spring能创建真实的Service实例(如果依赖都能初始化的话),那你的测试就会跑真实的Service逻辑,完全失去Mock的意义。
4. @MockBean只能用在控制器测试里吗?为什么?
当然不是。@MockBean的核心作用是替换Spring上下文里的任意Bean,只要是在加载Spring上下文的测试场景里都能用——比如用@SpringBootTest做集成测试时,你想Mock某个数据库Repository、远程调用的Feign客户端、甚至是自定义的配置类Bean,都可以用@MockBean。只是@WebMvcTest是控制器测试的常用注解,所以大家经常看到它在这里被使用而已,和控制器本身没有绑定关系。
内容的提问来源于stack exchange,提问作者vi0

