很多J2EE应用都是基于Spring的,一些比较复杂的测试用例,如果用基于TestCase比较难满足全部的测试场景。
所以,我们会用到一些Mock工具,如PowerMockito:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.4.10</version>
<scope>test</scope>
</dependency>
但用PowerMockito去MockSpring容器管理的实例,有些时候会存在一些问题,利用MiniTestCase可以避免。也可以基于MiniTestCase扩展出更复杂的TestCase。
TestCase如下:
package com.x.commons.test;
import javax.management.InstanceNotFoundException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
public class UserServiceTest extends MiniTestCase {
private static IUserService userService = new UserServiceImpl();
/**
* @throws Exception
*
*/
public UserServiceTest() throws Exception {
// TODO Auto-generated constructor stub
/**
* UserServiceImpl类属性userDao由Spring注入和维护。
* 当然,也可以将UserServiceImpl类内的属性全部Mock。如:super(userService);
*/
super(userService, IUserCommon.class);
}
/**
* Test method for {@link com.x.commons.test.UserServiceImpl#reg(java.lang.String, java.lang.String)}.
* @throws InstanceNotFoundException
*/
@Test
public void testReg() throws InstanceNotFoundException {
try {
PowerMockito.doReturn(false).when(mock("userCommon", IUserCommon.class)).isExist(Mockito.anyString());
User user = userService.reg("zhangsan", "123456");
Assert.assertEquals(user.getUname(), "zhangsan");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* Test method for {@link com.x.commons.test.UserServiceImpl#findById(long)}.
*/
@Test
public void testFindById() {
try {
User u2 = userService.findById(1);
Assert.assertEquals(u2.getUname(), "x");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
UserServiceImpl如下:
package com.x.commons.test;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service("userService")
public class UserServiceImpl implements IUserService {
@Resource
private IUserDao userDao;
@Resource
private IUserCommon userCommon;
/**
* @see com.x.commons.test.IUserService#reg(java.lang.String, java.lang.String)
*/
@Override
public User reg(String uname, String upwd) {
// TODO Auto-generated method stub
if (userCommon.isExist(uname)) {
return null;
}
User user = new User(uname, upwd);
userDao.add(user);
return user;
}
/**
* @see com.x.commons.test.IUserService#findById(long)
*/
@Override
public User findById(long uid) {
// TODO Auto-generated method stub
return userDao.findById(uid);
}
}
package com.x.commons.test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.management.InstanceNotFoundException;
import org.powermock.api.mockito.PowerMockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.transaction.GlobalTransactionalTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
@TransactionConfiguration(defaultRollback = true)
@TestExecutionListeners(GlobalTransactionalTestExecutionListener.class)
@ContextConfiguration(locations = {"classpath:application.xml"})
public abstract class MiniTestCase extends AbstractJUnit4SpringContextTests {
private final Object testTargetObject;
private AtomicBoolean init = new AtomicBoolean(false);
private Logger logger = LoggerFactory.getLogger(getClass());
private ConcurrentHashMap<Object, Object> mockObjectSet = new ConcurrentHashMap<Object, Object>();
private List<Class<?>> testTargetFields = null;
/**
*
* @param testTargetClass 被测试的目标类
* @param testTargetField 被Mock testTargetClass属性。该参数可为空,为空时会Mock testTargetClass的所有属性。
*/
public MiniTestCase(Object testTargetObject, Class<?>... testTargetField) throws Exception{
// TODO Auto-generated constructor stub
if (testTargetObject == null) {
IllegalArgumentException illegalArgumentException = new IllegalArgumentException(" 'testTargetObject' Can't be null");
logger.error("", illegalArgumentException);
throw illegalArgumentException;
}
this.testTargetObject = testTargetObject;
if (testTargetField != null) {
this.testTargetFields = Arrays.asList(testTargetField);
}
try {
initMock(testTargetObject);
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("", e);
throw e;
}
}
private void initMock(Object object) throws IllegalArgumentException, IllegalAccessException{
logger.debug("正在初始化 MiniTestCase ...");
if (init.compareAndSet(false, true)) {
Class<? extends Object> cls = object.getClass();
procField(getFields(cls));
logger.debug("初始化完成 MiniTestCase .");
}
}
private void procField(List<Field> targetFieldList) throws IllegalArgumentException, IllegalAccessException{
if (targetFieldList == null || targetFieldList.isEmpty()) {
return;
}
for (Field field : targetFieldList) {
Class<?> typeOfTargetObject = field.getType();
if (testTargetFields != null &&
!testTargetFields.isEmpty() &&
!testTargetFields.contains(typeOfTargetObject)) {
continue;
}
int modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
Object mock = PowerMockito.mock(typeOfTargetObject);
mockObjectSet.putIfAbsent(field.getName(), mock);
setField(field, mock);
}
}
}
private void setField(Field field, Object mock) throws IllegalArgumentException, IllegalAccessException{
field.setAccessible(true);
field.set(testTargetObject, mock);
}
private List<Field> getFields(Class<?> targetClass) {
List<Field> list = new ArrayList<Field>();
list.addAll(Arrays.asList(targetClass.getDeclaredFields()));
return list;
}
protected <T> T mock(String fieldName, Class<T> t) throws InstanceNotFoundException{
Object object = mockObjectSet.get(fieldName);
if (object == null) {
throw new InstanceNotFoundException("Mock '"+fieldName+"' Object is not found!!");
}
logger.debug("成功Mock '" + fieldName +"' 实例.");
return t.cast(object);
}
}