在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等方法來模擬輸入,去測試相關的代碼片段。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM