轉載: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對象,使得代碼簡潔干凈。
