在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等方法來模擬輸入,去測試相關的代碼片斷。
相關文章
相關標籤/搜索