转载: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注入使用的更多相关文章

  1. 基于spring与mockito单元测试Mock对象注入

    转载:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.关键词 单元测试.spring.mockito 2.概述 单 ...

  2. Mockito中@Mock与@InjectMock

    Mockito是java单元测试中,最常用的mck工具之一,提供了诸多打桩方法和注解.其中有两个比较常用的注解,@Mock和@InjectMock,名字和在代码中使用 的位置都很像,对于初学者,很容易 ...

  3. Mockito 如何 mock 返回值为 void 的方法

    转载:https://unmi.cc/mockito-how-to-mock-void-method/#more-7748 最初接触 Mockito 还思考并尝试过如何用它来 mock 返回值为 vo ...

  4. dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito)

    转:http://blog.csdn.net/yys79/article/details/66472797 最近,项目中频繁用到dubbo,而且java工程用引用了几十个关联系统的服务(如用户认证,基 ...

  5. Mockito如何mock一条链式调用

    在写单元测试的时候,不免可能需要mock一些对象出来,并且mock一些方法调用去返回一个自己想要的对象.一般的使用是这样的: FinalPumpkin pumpkin = mock(FinalPump ...

  6. java中将list、map对象写入文件

    链接地址:http://blog.sina.com.cn/s/blog_4a4f9fb50101p6jv.html     推荐:凤爪女瓜子男怪象该谁反思伦敦房价为什么持续暴涨 × wvqusrtg个 ...

  7. 简单介绍如何使用PowerMock和Mockito来mock 1. 构造函数 2. 静态函数 3. 枚举实现的单例 4. 选择参数值做为函数的返回值(转)

    本文将简单介绍如何使用PowerMock和Mockito来mock1. 构造函数2. 静态函数3. 枚举实现的单例4. 选择参数值做为函数的返回值5. 在调用mock出来的方法中,改变方法参数的值 一 ...

  8. 持续集成之路 —— Mock对象引起的测试失败

    今天遇到了一个很奇怪的问题,纠结了好久.在和同事念叨这个问题时,突然想到了问题所在. 问题现象: 在一个Service的单元测试类中有八个测试用例,单独运行时都可以正常通过.可是一旦一起运行时,总是会 ...

  9. Mockito不能mock final类的解决办法

    Mockito是很常用的测试工具,使用过程中可能会遇到下面的问题: Mockito cannot mock/spy because : - final class 问题重现: 引入该依赖到项目的mav ...

随机推荐

  1. 用C扩展Python3

    官方文档: https://docs.python.org/3/extending/index.html 交叉编译到aarch64上面 以交叉编译到aarch64上面为例,下面是Extest.c的实现 ...

  2. redis缓存web session

    redis缓存web session 首先说下架构图.使用Redis作为会话服务器,统一管理Session.如图,集群里的WEB服务器共享存放在REDIS里面全部的客户端SESSION. 当然,反向代 ...

  3. Xcode6 itunes完美打包api 方法

    转:http://bbs.csdn.net/topics/390948190 Xcode6 itunes完美打包api 方法! 特点轻盈小巧,方便快捷!

  4. 如何让xcode自动检查内存泄露

    在project-setting中找到 “Run Static Analyzer” 键,然后把值修改为“YES”.这样在编码的时候,xcode就可以自动为我们检查内存泄露了. 原图片:http://b ...

  5. 由pushViewController说起可能出线的各种死法

    做苹果开发或者果粉对导航条这个东西应该都不陌生,这咚咚在小小的屏幕上通过一个简单的View的队列管理来做到手机界面的有条理管理,但是开发过程程序员可能碰到各种死法,下面分享一二.            ...

  6. unity3d 5.6烘焙教程

    unity5.6是今年发布,作为5.x的最后一个版本,有很多烘焙优势,在此总结一些作为5.x系列完结的笔记这个版本在烘焙上的特点就是增加了渐进光照贴图(Progressive Lightmapper) ...

  7. 关于 java,nio,bufferedreader,bytebuffer

    有没有一种方法来读取的ByteBuffer有一个BufferedReader,而无需将其转换为String优先?我想读通过一个相当大的 ByteBuffer作为文本行和我想避免它写入磁盘性能方面的原因 ...

  8. Windows下LuaJIT的编译和使用

    1.下载LuaJIT,download>> 2.编译 开始 –> 程序 –> Microsoft Visual Studio xx –> Visual Studio To ...

  9. maven 阿里仓库

    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3. ...

  10. 详细解读Volley(五)—— 通过源码来分析业务流程

    一.初始化请求队列并运行 我们用Volley时,最先开始的就是初始化请求队列,一种常见的写法如下: public class MyApplication extends Application { p ...