现在的位置: 首页 > 综合 > 正文

基于Spring的PowerMockito TestCase

2019年06月18日 ⁄ 综合 ⁄ 共 5798字 ⁄ 字号 评论关闭

很多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);
    }
}

【上篇】
【下篇】

抱歉!评论已关闭.