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

轉載: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對象,使得代碼簡潔乾淨。
相關文章
相關標籤/搜索