1. 程式人生 > >基於spring與mockito單元測試Mock對象註入

基於spring與mockito單元測試Mock對象註入

err else archive ali spro 反射 lse ica sce

轉載:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.關鍵詞   單元測試、spring、mockito   2.概述   單元測試目前已經成為項目中保證代碼質量的一種必要方法,對於一些不易構造或者不易獲取的對象通過mock的方式進行測試是一種很有效的處理辦法。在基於spring的mock測試中,mock對象獲取和使用的便利性可以提升單元測試代碼的質量。   3.實現原理   Mock對象的註入使用註解和反射,對象註入依賴spring框架支持junit4提供的TestExcutionListeners監聽器對象,在監聽器中將mock對象註入到單元測試類中。   4.新建對象方式代碼
private IAccessServiceaccessService = Mockito.mock(IAccessService.class); @BeforeClass public static void beforeClass(){ // 構造並註入Mock對象ICmsProxyService sceneConfigService.setAccessService(accessService); }
  5.監聽器方式代碼   5.1 實現監聽器   繼承DependencyInjectionTestExecutionListener類,   實現injectDependencies(TestContexttestContext)方法
public class MockitoDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener { @Override protected void injectDependencies(TestContext testContext) throws Exception { super.injectDependencies(testContext); init(testContext); }
  5.2 利用反射註入mock對象
private void init(final TestContext testContext)throws Exception { Object bean = testContext.getTestInstance(); Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { Annotation[] annotations = field.getAnnotations(); for (Annotation annotation : annotations) { if(annotationinstanceof Mock){ //註入Mock實例 MockObject obj = new MockObject(); obj.setType(field.getType()); obj.setObj(Mockito.mock(field.getType())); field.setAccessible(true); field.set(bean, obj.getObj()); mockObjectMap.put(field.getName(), obj); }else if(annotation instanceofAutowired){ injectFields.add(field); } } }


AutowireCapableBeanFactory factory =testContext.getApplicationContext().getAutowireCapableBeanFactory(); //Autowired註解註入mock對象 for (Field field :injectFields) { field.setAccessible(true); Object object = field.get(bean); if(objectinstanceof Proxy){ Class targetClass = AopUtils.getTargetClass(object); if(targetClass ==null) return; Field[] targetFields =targetClass.getDeclaredFields(); for(Field targetField : targetFields){ targetField.setAccessible(true); if(mockObjectMap.get(targetField.getName()) ==null){ continue; } targetField.set(getTargetObject(object,mockObjectMap.get(targetField.getName()).getType()),mockObjectMap.get(targetField.getName()).getObj()); } }else{ Object realObject = factory.getBean(field.getName()); if(null != realObject){ Method[] methods = realObject.getClass().getDeclaredMethods(); for (Method method : methods) { if(method.getName().equalsIgnoreCase("set" +field.getName())){ method.invoke(realObject, mockObjectMap.get(field.getName()).getObj()); } } } } } }
  5.3 測試類配置   使用@TestExecutionListeners註解,引入監聽器,需要mock的對象加上@Mock註解。
@TestExecutionListeners({MockitoDependencyInjectionTestExecutionListener.class}) public class AccessServiceImplTest extends BaseTestCase{ @Autowired private IAccessServiceaccessService; @Mock private IPersonServicepersonService; @Mock private IAccessDaoaccessDao; }
  6.總結   監聽器的方式解放了代碼中硬編碼註入mock對象,使得代碼簡潔幹凈。

基於spring與mockito單元測試Mock對象註入