Java Web并发单元测试摘记(1)

大的web项目开发和运行环境都在服务器容器中进行为主,包括调试过程,也都是单例进过Web触发进行测试。在Web项目中设计使用Spring、hibernate、JBPM工作流、ehcache各种框架或组件。这些东西在一起配置好一个有效的、覆盖所有环境的单元测试用例也比较复杂。所有配置好一个可用有效的单元测试环境十分必要。并且面对单元测试对并发要求的不支持,还得加入必要的并发测试组件,满足测试全面系统白盒测试要求。

这里总结几种有效的配置单元测试方式:

1、直接使用Junit4组件,进行简单单元测试,在setUp()中初始化各种测试环境如下:

@Override
	protected void setUp() throws Exception {
		super.setUp();
		String[] paths = { "classpath:applicationContext.xml" };
		ApplicationContext ctx = new ClassPathXmlApplicationContext(paths);
		SpringContextListener.setApplicationContext(ctx);
		// ############模拟servlet容器启动,手动更改配置文件路径
		Constant.CURRENT_PROJECT_PATH = "src/";
		// ############直接容器中获取bean
		userManager = (UserManager) ctx.getBean("userManager");
		userService = (UserService) ctx.getBean("userService");
	}

2、使用Sprint-test.jar框架,支持事务可注解方式启动的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=false) //true将会回滚所有操作,默认没有该注解为回滚
public class JBPMProcessTest2 extends  AbstractTransactionalJUnit4SpringContextTests{

以上都只能暂时支持简单功能的单元测试。但是要测试并发和压力等。需要加入一个常用的框架,支持在单元测试中注入多线程和并发。

具体参见:http://blog.csdn.net/zhangyaoming2004/article/details/7619489下面附有Jar包下载http://yunpan.cn/QUtVay66VnU4T

我们具体使用的功能不是很多,这些并发测试可以嵌入到上面两种单元测试方式中:如下:

/**
 * 
 */
package com.dtsz.model.service.test;

import net.sourceforge.groboutils.junit.v1.TestRunnable;

import com.dtsz.model.entity.report.common.InvokeSource;
import com.dtsz.model.service.ExcelReportLogicService;
import com.dtsz.model.service.TaskLogicService;
import com.dtsz.model.util.ExcelReportUtil;
import com.dtsz.view.vo.authenticator.UserVO;
import com.dtsz.view.vo.webservice.ExcelReportResult;

/**
 * 模拟插件端数据上报的并发操作测试
 * 
 * @author xiaoli
 * 
 */
public class CreateMulltiTaskReportGroboThread extends TestRunnable {

	TaskLogicService taskLogicService;
	ExcelReportLogicService excelReportLogicService;
	
	private String reportMap;
	private UserVO user;
	private InvokeSource invokeSource;
	private String bbq;
	
	public CreateMulltiTaskReportGroboThread(String reportMap, UserVO user, InvokeSource invokeSource,String bbq) {
		super();
		this.reportMap = reportMap;
		this.user = user;
		this.invokeSource = invokeSource;
		this.bbq = bbq;
		init();
	}
	
	public void init() {
		taskLogicService = (TaskLogicService)ExcelReportUtil.getBean("taskLogicService");
		excelReportLogicService = (ExcelReportLogicService)ExcelReportUtil.getBean("excelReportLogicService");
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.sourceforge.groboutils.junit.v1.TestRunnable#runTest()
	 */
	@Override
	public void runTest() throws Throwable {
		// TODO Auto-generated method stub
		// ########################模拟当前任务该报表期任务上报
		//保存数据
		ExcelReportResult result = taskLogicService.reportData(reportMap, user, invokeSource);
		excelReportLogicService.saveData(result);
		System.out.println("报表期为:"+this.bbq+"已上报"); 
	}

}

单元测试并发:

/**
 * 
 */
package com.dtsz.model.service.test;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;
import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.dtsz.model.entity.authenticator.User;
import com.dtsz.model.entity.report.common.InvokeSource;
import com.dtsz.model.service.authenticator.UserManager;
import com.dtsz.model.service.authenticator.UserService;
import com.dtsz.model.service.exception.BaseAppException;
import com.dtsz.model.util.BeanUtil2;
import com.dtsz.model.util.Constant;
import com.dtsz.model.util.Encryption;
import com.dtsz.view.util.SpringContextListener;
import com.dtsz.view.vo.authenticator.UserVO;

/**
 * 模拟数据上报,这里的初始化数据根据插件端传入数据组合来的,当前只有根据报表期生成初始化数据
 * 
 * @author xiaoli
 * 
 */
public class CreateMultiTaskReportTest3 extends TestCase {


	private UserManager userManager;

	private UserService userService;

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		String[] paths = { "classpath:applicationContext.xml" };
		ApplicationContext ctx = new ClassPathXmlApplicationContext(paths);
		SpringContextListener.setApplicationContext(ctx);
		// ############模拟servlet容器启动,手动更改配置文件路径
		Constant.CURRENT_PROJECT_PATH = "src/";
		// ############直接容器中获取bean
		userManager = (UserManager) ctx.getBean("userManager");
		userService = (UserService) ctx.getBean("userService");
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}

	@Test
	public void test(){

		// ###########自动生成报表期串集合
		List bbqs = new ArrayList();
		UnitTestUtils.imitateCreateMultiBbq(bbqs, 2, "2048", "5");

		// 创建线程
		TestRunnable[] tr = new TestRunnable[bbqs.size()];
		int processCount = 0;

		// ##########对这些数据进行填报
		for (String bbq : bbqs) {
			// 模拟上报数据
			String reportMap = "{taskID:\"402880ee425a92f501425aa75ad50002\",bbq_:\""
					+ bbq
					+ "\""
					+ ",bbhid:\"402855b942099b1b014209b1177e03f5\",approvalFlag:2,reportFlag:False,auditFlag:False,sheetMap:"
					+ "[{id:\"402880ee425a92f501425aa75ad60004\",sheetType:\"BASIC\",values:{}}]}";
			// 模拟上报的user
			UserVO user = null;
			try {
				user = checkUser("xl1", "1");
			} catch (BaseAppException e) {
				e.printStackTrace();
			} // 模拟插件端checkUser
			String sessionInfo = "{institutionname:\"南昌分行\",institutioncode:\"A01NC\",username:\"肖力1"
					+ "1\",usercode:\"xl1\",rolecode:\"null\",bbhId:\"402855b942099b1b014209b1177e03f5\",bbhcode:\"B01b\",btype:\"BASIC\",taskid:\"402880ee425a92f501425a"
					+ "a75ad50002\",bbhname:\"基层财务b\",bbq:\"" + bbq
					+ "\",frequency:\"MONTH\",SESSIONDIMENSION:{}}";
			try {
				userService.updateSession(sessionInfo, user);
			} catch (BaseAppException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			} // 模拟插件端updateSession
			// 初始化上报方式
			InvokeSource invokeSource = InvokeSource.WSCALL;

			CreateMulltiTaskReportGroboThread reportThread = new CreateMulltiTaskReportGroboThread(reportMap,user, invokeSource,bbq);
			tr[processCount] = reportThread;
			processCount++;
		}
		System.out.println("#######################################计时开始########################"); 
		long startTime = System.currentTimeMillis();
		// 生成测试线程运行器
		MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(tr);
		// 运行测试线程
		try {
			mttr.runTestRunnables();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("#######################一共耗时:"
				+ String.valueOf((System.currentTimeMillis() - startTime) / 1000) + "秒");
	}

	/**
	 * xl1 1
	 * */
	public UserVO checkUser(String userid,
			String password) throws BaseAppException {
		Map paramMap = new HashMap();
		paramMap.put("UserName", userid);
		paramMap.put("Password", password);
		List users = userManager.findByCodeCache(userid);
		List needUsers = new ArrayList();
		if (users != null && users.size() > 0) {
			for (User user : users) {
				if (user.getState() && user.getCode().equals(userid)
						&& user.getPassword().equals(Encryption.encryption(password))) {
					needUsers.add(user);
				}
			}
		}
		// 通过验证
		if (needUsers != null && needUsers.size() > 0) {
			User user = needUsers.get(0);
			// 获取用户权限,并存放于session中
			// UserVO userVO = userManager.getUserPermission(user.getId());
			String ipAddress = "0.0.0.0";
			UserVO userVO = new UserVO();
			BeanUtil2.copyProperties(user, userVO);
			userVO.setIpAddress(ipAddress);
			return userVO; // 通过验证
		} else {
			return null;
		}

	}

}

真实环境并发和压力测试不仅仅是在多个线程同时启动在测,还可能是增量式压力测试。这些还是要封装好和处理好。


还在进行中……

你可能感兴趣的:(Java Web并发单元测试摘记(1))