很多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); } }
MiniTestCase如下:
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); } }