在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等方法来模拟输入,去测试相关的代码片断。
相关文章
相关标签/搜索