在SpringTest中将Mockito的mock对象通过spring注入使用
转载:https://blog.csdn.net/m0_38043362/article/details/80111957
1. 原理介绍
通过BeanFactoryPostProcessor向BeanFactory中注册需要进行Mock的对象,使当前Bean容器在依赖注入时使用
我们提供的Mock对象注入到实例中使用。
具体需要交给容器管理的mock实例,是通过TestExecutionListener在容器开始启动前去解析当前测试类中的使用@Mock
注解的字段,然后根据类型创建对应的Mock实例,将创建出来的Mock实例通过BeanFactoryPostProcessor注册到容器中,
以供依赖注入使用。
2.代码实现
注册Mock实例部分
public class MockitoBeansPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<Class<?>, MockitoBeansTestExecutionListener.MockBeanWrapper> allMockBeans = MockitoBeansTestExecutionListener.resolvedAllMockBeans();
for (Map.Entry<Class<?>, MockitoBeansTestExecutionListener.MockBeanWrapper> mockBeanWrapperEntry : allMockBeans.entrySet()) {
beanFactory.registerResolvableDependency(mockBeanWrapperEntry.getKey(), mockBeanWrapperEntry.getValue().getMockObject());
}
}
}
解析@Mock注解部分
public class MockitoBeansTestExecutionListener extends AbstractTestExecutionListener {
private static final Map<Class<?>, MockBeanWrapper> mockBeans = new ConcurrentHashMap<>(30);
private static final Map<Class<?>, List<Field>> injectMockBeans = new ConcurrentHashMap<>(30);
private static boolean hasInitialized = false;
public static Map<Class<?>, MockBeanWrapper> resolvedAllMockBeans() {
Assert.isTrue(hasInitialized);
return Collections.unmodifiableMap(mockBeans);
}
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
Field[] declaredFields = testContext.getTestClass().getDeclaredFields();
//将需要mock的对象创建出来
for (Field field : declaredFields) {
Mock mockAnnon = field.getAnnotation(Mock.class);
if (mockAnnon != null) {
MockBeanWrapper wrapper = new MockBeanWrapper();
Class<?> type = field.getType();
wrapper.setMockObject(Mockito.mock(type));
wrapper.setBeanType(type);
wrapper.setBeanName(field.getName());
mockBeans.putIfAbsent(wrapper.getBeanType(), wrapper);
injectMockBeans.compute(testContext.getTestClass(), (targetClass, waitInjectFields) -> {
if (waitInjectFields == null) {
waitInjectFields = new ArrayList<>();
}
waitInjectFields.add(field);
return waitInjectFields;
});
}
}
hasInitialized = true;
}
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
Object testInstance = testContext.getTestInstance();
List<Field> fields = injectMockBeans.get(testContext.getTestClass());
if (fields != null) {
for (Field field : fields) {
field.setAccessible(true);
field.set(testInstance, mockBeans.get(field.getType()).getMockObject());
}
}
}
public class MockBeanWrapper {
private String beanName;
private Class<?> beanType;
private Object mockObject;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public Class<?> getBeanType() {
return beanType;
}
public void setBeanType(Class<?> beanType) {
this.beanType = beanType;
}
public Object getMockObject() {
return mockObject;
}
public void setMockObject(Object mockObject) {
this.mockObject = mockObject;
}
}
}
3.使用Demo
MessageSupplier是将要进行Mock的接口
public interface MessageSupplier {
String getMessage();
}
这个是依赖MessageSupplier的实例类
@Service
public class SomeService {
@Autowired
MessageSupplier messageSupplier;
public void printMessage() {
System.out.println(messageSupplier.getMessage());
}
}
单元测试类
@TestExecutionListeners({MockitoBeansTestExecutionListener.class})
@ContextConfiguration(classes = {SimpleTestCase.class})
@ComponentScan(basePackageClasses = {SimpleTestCase.class})
public class SimpleTestCase extends AbstractJUnit4SpringContextTests {
@Autowired
private SomeService someService;
@Mock
MessageSupplier messageSupplier;
@Test
public void test() {
doReturn("this is mock message.")
.when(messageSupplier)
.getMessage();
someService.printMessage(); //输出this is mock message.
}
@Bean
public BeanFactoryPostProcessor mockBeansPostProcessor(){
return new MockitoBeansPostProcessor();
}
}
4.总结
在使用微服务的系统架构中,做一次单元测试会比较麻烦,可能需要启N多关联服务或者去连接N多关联服务。
这就使得单元测试很难实行,在这种情况下可以通过上面的方法将在本模块中不存在的实例都通过Mock实例
使用,这样使用Mockito中的doReturn等方法来模拟输入,去测试相关的代码片段。
在SpringTest中将Mockito的mock对象通过spring注入使用的更多相关文章
- 基于spring与mockito单元测试Mock对象注入
转载:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.关键词 单元测试.spring.mockito 2.概述 单 ...
- Mockito中@Mock与@InjectMock
Mockito是java单元测试中,最常用的mck工具之一,提供了诸多打桩方法和注解.其中有两个比较常用的注解,@Mock和@InjectMock,名字和在代码中使用 的位置都很像,对于初学者,很容易 ...
- Mockito 如何 mock 返回值为 void 的方法
转载:https://unmi.cc/mockito-how-to-mock-void-method/#more-7748 最初接触 Mockito 还思考并尝试过如何用它来 mock 返回值为 vo ...
- dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito)
转:http://blog.csdn.net/yys79/article/details/66472797 最近,项目中频繁用到dubbo,而且java工程用引用了几十个关联系统的服务(如用户认证,基 ...
- Mockito如何mock一条链式调用
在写单元测试的时候,不免可能需要mock一些对象出来,并且mock一些方法调用去返回一个自己想要的对象.一般的使用是这样的: FinalPumpkin pumpkin = mock(FinalPump ...
- java中将list、map对象写入文件
链接地址:http://blog.sina.com.cn/s/blog_4a4f9fb50101p6jv.html 推荐:凤爪女瓜子男怪象该谁反思伦敦房价为什么持续暴涨 × wvqusrtg个 ...
- 简单介绍如何使用PowerMock和Mockito来mock 1. 构造函数 2. 静态函数 3. 枚举实现的单例 4. 选择参数值做为函数的返回值(转)
本文将简单介绍如何使用PowerMock和Mockito来mock1. 构造函数2. 静态函数3. 枚举实现的单例4. 选择参数值做为函数的返回值5. 在调用mock出来的方法中,改变方法参数的值 一 ...
- 持续集成之路 —— Mock对象引起的测试失败
今天遇到了一个很奇怪的问题,纠结了好久.在和同事念叨这个问题时,突然想到了问题所在. 问题现象: 在一个Service的单元测试类中有八个测试用例,单独运行时都可以正常通过.可是一旦一起运行时,总是会 ...
- Mockito不能mock final类的解决办法
Mockito是很常用的测试工具,使用过程中可能会遇到下面的问题: Mockito cannot mock/spy because : - final class 问题重现: 引入该依赖到项目的mav ...
随机推荐
- JSONPATH使用方法
如下的json: { "store": { "book": [ { "category": "reference", & ...
- 解决winform中mdi子窗体加载时显示最大化最小化按钮的方法
场景:在mid加载子窗体的时候如果指定WindowState为Maximized,加载完成后主窗体会显示最大化.最小化.关闭的按钮图标. 解决方法: 1.更改主窗体FormMain的属性.制定Main ...
- DbContextScope,A simple and flexible way to manage your Entity Framework DbContext instances,by mehdime
DbContextScope A simple and flexible way to manage your Entity Framework DbContext instances. DbCont ...
- Visual Studio断点调试, 无法监视变量, 提示无法计算表达式
在使用Visual Studio 2012进行断点调试时,对某个变量添加监视,出现"无法计算表达式"的提示. 解决办法:依次点击菜单栏中的"调试"→" ...
- Delphi取UTC时间秒
自格林威治标准时间1970年1月1日00:00:00 至现在经过多少秒数时间模块Uses DateUtils;当前时间:中国是 +8时区,换成UTC 就要减掉8小时showMessage(intt ...
- Xcode 5.1.1 与 Xcode 6.0.1 的共存之路(建议大家在升级Xcode 6.0.1 的时候保留Xcode 5.1.1)
最近升级了Xcode 6.0.1 与原有项目有不少冲突.建议大家谨慎升级,同时做好备份.二者共存推荐如下帖子. http://jingyan.baidu.com/article/1612d500457 ...
- UITableView分割线样式与颜色
tv.separatorStyle = UITableViewCellSeparatorStyleSingleLine; //设置样式 tv.separatorColor = [UIColor c ...
- arcgis导oracle多步操作产生错误。请检查每一步的状态值。" 如何解决?
你知你用的什么数据引擎,ADO? 我以前碰过类似的,我有两个方案: 1.升ado到2.7以上 2.不要用microsoft oledb provider for oracle,而要用or ...
- 【JVM】linux上tomcat中部署的web服务,时好时坏,莫名其妙宕机,报错:There is insufficient memory for the Java Runtime Environment to continue.
=========================================================================================== 环境: linu ...
- 在MFC内竟然不可以解析“Mat”
调试了好久,在MFC内竟然不可以解析“Mat” 总是显示"Mat"没有定义,改动include.lib.依赖库, 不断地改动: #include "opencv2/img ...