今天在对基于Spring mvc架构的项目写单元测试的时候,本来想用@RunWith的方式轻松搞定它。不曾想还不是那么so easy,
一方面是controller层没有联系起来,再者就是SpringJUnit4ClassRunner启动就报不知道什么鬼错了。索性就换成mock方式,再熟悉一下spring容器加载机制也未尝不是一件好事~ 废话少说,直接上代码先!!!
测试基类
package com.andy.test;
import java.io.File;
import java.util.Arrays;
import java.util.Map;
import javacommon.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping;
/**
*
* Spring MVC 3.0 Controller层测试基类
* 提供Controller层测试stub
*
* @author Andy
* @since 2012.5.10 1:25 PM
* @version 1.0
*
*/
public abstract class AbstractTestCase {
// 应用程序根配置文件(不包含applicationContext.xml配置文件)
private final static String[] ROOT_CONFIGLOCATION = {"classpath:/spring/*-test.xml"};
// 随Servlet启动时加载配置文件。(默认为applicationContext.xml/servletName-servlet.xml)
private final static String DEFAULT_CONFIG_LOCATION = "classpath:/spring/applicationContext.xml";
// 模块功能CRUD
protected final static String MODULE_QUERY = "query";
protected final static String MODULE_LIST = "list";
protected final static String MODULE_SHOW = "show";
protected final static String MODULE_CREATE = "create";
protected final static String MODULE_SAVE = "save";
protected final static String MODULE_EDIT = "edit";
protected final static String MODULE_DELETE = "delete";
// Logger
protected final static Logger logger;
// 对象映射处理器(映射到controller类)
protected HandlerMapping handlerMapping;
// 方法适配处理器(映射到具体方法)
protected HandlerAdapter handlerAdapter;
// Spring容器上下文
protected XmlWebApplicationContext webApplicationContext;
static{
// 清除旧的测试日志文件
File logFile = null;
logFile = new File("logs/test.log");
if(logFile.exists()){
logFile.setReadable(true);
logFile.setWritable(true);
logFile.delete();
}
// 加载测试日志配置文件
PropertyConfigurator.configure(AbstractTestCase.class.getResource("/log4j-test.properties"));
logger = Logger.getLogger(AbstractTestCase.class);
}
@Before
public void setUp(){
// 创建web应用程序根上下文,该上下文解析并管理系统实例
XmlWebApplicationContext rootWebApplicationContext = new XmlWebApplicationContext();
rootWebApplicationContext.setConfigLocations(ROOT_CONFIGLOCATION);
// 创建servletContext上下文
MockServletContext servletContext = new MockServletContext();
rootWebApplicationContext.setServletContext(servletContext);
rootWebApplicationContext.refresh();
//servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWebApplicationContext);
// 创建web应用程序上下文,管理controller层请求业务
webApplicationContext = new XmlWebApplicationContext();
webApplicationContext.setConfigLocation(DEFAULT_CONFIG_LOCATION);
webApplicationContext.setParent(rootWebApplicationContext);
webApplicationContext.refresh();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webApplicationContext);
// 获取默认mapping,adapter
handlerMapping = webApplicationContext.getBean(ControllerClassNameHandlerMapping.class);
handlerAdapter = webApplicationContext.getBean(AnnotationMethodHandlerAdapter.class);
}
// TODO 测试流程 创建->修改->查询-> 删除
@Test
public void testMain(){
// 创建
this.testCreateUI();
this.testSave();
// 修改
this.testEditUI();
this.testUpdate();
// 查询
this.testQuery();
this.testList();
this.testShow();
// 删除
this.testDelete();
}
/**
* 跳转到创建UI
*/
protected abstract void testCreateUI();
/**
* 创建功能
*/
protected abstract void testSave();
/**
* 跳转到编辑UI
*/
protected abstract void testEditUI();
/**
* 修改功能
*/
protected abstract void testUpdate();
/**
* 按条件查询
*/
protected abstract void testQuery();
/**
* 分页查询所有记录
*/
protected abstract void testList();
/**
* 查询某条记录详情
*/
protected abstract void testShow();
/**
* 删除某条记录
*/
protected abstract void testDelete();
/**
* 执行请求
* @param request http请求对象
* @param response http响应对象
* @return UI信息
*/
protected ModelAndView execute(HttpServletRequest request , HttpServletResponse response){
try {
HandlerExecutionChain chain = handlerMapping.getHandler(request);
return handlerAdapter.handle(request, response, chain.getHandler());
} catch (Exception e) {
// TODO 忽略 no thread bind request exception。
// 如报错,在业务方法引入HttpServletRequest即可。(eg. public void save(HttpServletRequest request){ // statement})
}
return null;
}
/**
* 封装请求信息
* @param uri 请求uri
* @param method 请求类型 默认请求类型为GET
* eg POST GET PUT DELETE HEAD TRACE OPTIONS
* @param params 请求参数
* @return http请求对象
*/
protected HttpServletRequest createRequest(String uri , Map<String , String> params , RequestMethod... method ){
if(null == uri || uri.isEmpty()){
throw new IllegalArgumentException("It must contains request uri!");
}
// 构造请求
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(uri);
if(null == method || method.length == 0){
request.setMethod(RequestMethod.GET.name());
}else{
request.setMethod(method[0].name());
}
if(null != params && !params.isEmpty()){
request.addParameters(params);
}
return request;
}
@After
public void tearDown(){
}
// 查询相关
/**
* 查询所有数据记录
*
* @param module 当前模块
* @param operate 当前操作
*/
protected void list(String module, String operate){
ModelAndView view = this.processRequest(module + operate, null);
logger.info(StringUtils.format("【Unit Testing Info】query {0}: {1}.", module , view));
}
/**
* 查询某个记录详情
* @param module 当前模块
* @param operate 当前操作
* @param params 某记录数据参数
* @param method 请求类型
*/
protected void show(String module, String operate , Map<String,String> params , RequestMethod method){
Assert.notEmpty(params, "The request params is null!");
ModelAndView view = this.processRequest(module + operate, params, method);
logger.info(StringUtils.format("【Unit Testing Info】 query {0} by params {1}: {2}.", module , params, view));
}
/**
* 多条件查询数据
* @param module 当前模块
* @param operate 当前操作
* @param params 条件数据参数
* @param method 请求类型
*/
protected void query(String module, String operate , Map<String,String> params , RequestMethod method){
ModelAndView view = this.processRequest(module + operate, params, method);
logger.info(StringUtils.format("【Unit Testing Info】 query {0} by params {1}: {2}.", module , params, view));
}
// 创建修改相关
/**
* 请求待创建页面
*
* @param module 当前模块
* @param operate 当前操作
*/
protected void create(String module, String operate){
ModelAndView view = this.processRequest(module + operate, null);
logger.info(StringUtils.format("【Unit Testing Info】 {0} create url: {1}.", module , view));
}
/**
* 请求待修改页面
* @param module 当前模块
* @param operate 当前操作
* @param params 待数据参数
*/
protected void edit(String module, String operate , Map<String,String> params){
Assert.notEmpty(params, "The request params is null!");
ModelAndView view = this.processRequest(module + operate, params);
logger.info(StringUtils.format("【Unit Testing Info】 {0} edit url: {1}.", module , view));
}
/**
* 创建/修改数据请求
* @param module 当前模块
* @param operate 当前操作
* @param params 创建/修改数据参数
* @param method 请求类型
*/
protected void saveOrModify(String module, String operate , Map<String,String> params , RequestMethod method){
Assert.notEmpty(params, "The request params is null!");
this.processRequest(module + operate, params , method);
logger.info(StringUtils.format("【Unit Testing Info】 {0} save {1} success.", module , params));
}
// 删除操作
/**
* 删除数据请求
* @param module 当前模块
* @param operate 当前操作
* @param params 删除数据参数
*/
protected void delete(String module, String operate , Map<String,String[]> params){
Assert.notEmpty(params, "The request params is null!");
this.processRequest(module + operate, params);
logger.info(StringUtils.format("【Unit Testing Info】 {0} delete {1} success", module , Arrays.asList(params.get("ids"))));
}
/**
* 处理用户请求
*
* 实现构造请求数据,并发送请求,处理请求业务
*
* @param uri 请求uri
* @param method 请求类型 默认请求类型为GET
* eg POST GET PUT DELETE HEAD TRACE OPTIONS
* @param params 请求参数
* @return 请求结果
*/
@SuppressWarnings({"rawtypes" , "unchecked"})
protected ModelAndView processRequest(String uri , Map params , RequestMethod... method ){
HttpServletRequest request = this.createRequest(uri, params);
HttpServletResponse response = new MockHttpServletResponse();
return this.execute(request, response);
}
}
单元测试用例类
package com.andy.test.unit;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.RequestMethod;
import com.andy.dao.UserDao;
import com.andy.dao.RoleDao;
import com.andy.dao.RightsDao;
import com.andy.model.User;
import com.andy.model.Role;
import com.andy.model.Rights;
import com.andy.test.AbstractTestCase;
/**
* 用户管理模块测试用例
*
* @author Andy
* @since 2012.5.10 04:45 PM
* @version 1.0
*/
@SuppressWarnings("unchecked")
public class UserManagerTestCase extends AbstractTestCase{
// 用户管理包含子模块
private final static String USER_MODULE = "/user/";
private final static String ROLR_MODULE = "/role/";
private final static String RIGHTS_MODULE = "/rights/";
// 测试id
private Long userTestId;
private Long roleTestId;
private Long rightsTestId;
@Override
protected void testCreateUI() {
// TODO Auto-generated method stub
}
@Override
protected void testSave() {
// TODO Auto-generated method stub
}
@Override
protected void testEditUI() {
// TODO Auto-generated method stub
}
@Override
protected void testUpdate() {
// TODO Auto-generated method stub
}
@Override
protected void testQuery() {
// TODO Auto-generated method stub
}
@Override
protected void testList() {
// TODO Auto-generated method stub
}
@Override
protected void testShow() {
// TODO Auto-generated method stub
}
@Override
protected void testDelete() {
// TODO Auto-generated method stub
}
}
分享到:
相关推荐
Spring 3.0 是一个重要的Java应用程序框架,主要用于构建企业级的、基于组件的、松散耦合的应用程序。这个框架以其灵活性、可..."spring3.0 全部jar包"则为开发者提供了构建基于Spring 3.0应用程序所需的所有基础工具。
4. **注解驱动开发**:Spring 3.0大大扩展了注解的应用,例如@Controller、@Service、@Repository和@Service,它们分别用于标记控制器、服务层、数据访问层的类,简化了依赖注入。 5. **AOP增强**:Spring 3.0增强...
Spring 3.0大力推广了注解驱动的开发方式,如@Controller、@Service、@Repository和@Service等,减少了XML配置的使用,提升了开发效率。这些注解使组件的定义更加直观,降低了配置复杂性。 3. **AOP增强**: 在...
11. **Test支持**:Spring 3.0提供了Spring TestContext Framework,用于单元测试和集成测试,支持JUnit和TestNG。 在使用"spring 3.0.0"这个压缩包时,开发者需要确保包含所有必要的jar文件,例如`spring-beans....
11. **Spring Test**:Spring 3.0 强化了测试支持,提供了 `@ContextConfiguration` 和 `@Test` 等注解,使得单元测试和集成测试更为便捷。 12. **Web Flow**:Spring Web Flow 是 Spring 3.0 中的一个子项目,用于...
此外,Spring 3.0的MVC框架支持模板引擎,如FreeMarker和Velocity,简化了视图层的开发。 在数据访问和事务管理领域,Spring 3.0加强了JPA和Hibernate的支持,提供了更好的ORM集成。同时,它改进了对JDBC的支持,...
在Spring 3.0中,对依赖注入(Dependency Injection, DI)进行了优化,支持了基于注解的配置,开发者可以使用@Component、@Service、@Repository和@Controller等注解来声明bean,并通过@Autowired自动装配依赖。...
Spring 3.0提供了一套全面的测试工具,包括`@RunWith(SpringJUnit4ClassRunner.class)`用于Spring测试,以及模拟对象和数据源的工具,方便单元测试和集成测试。 这些只是Spring 3.0框架中的一部分关键特性,其丰富...
Spring 3.0提供模拟HTTP请求的MockMvc工具,方便进行单元测试和集成测试。测试控制器的逻辑变得更加简单,提高了代码质量。 总结: Spring 3.0 MVC以其优秀的架构设计、丰富的功能和高度的灵活性,成为Java Web开发...
8. **Spring Test**:测试模块提供了对Spring应用进行单元测试和集成测试的支持,包括ApplicationContext的加载和模拟对象的使用,便于进行测试驱动开发(TDD)。 9. **Spring Expression Language (SpEL)**:...
首先,Spring 3.0的一大亮点是增强了对Java 5和6的支持,引入了基于注解的配置,大大减少了XML配置文件的数量和复杂性。开发者可以使用如`@Autowired`、`@Service`、`@Repository`和`@Controller`等注解,直接在类或...
2. **AOP(Aspect Oriented Programming, 面向切面编程)**:Spring 3.0对AOP进行了优化,支持更多样化的切面定义,包括基于注解的切面,使得事务管理、日志记录等横切关注点的处理更加简洁。 3. **MVC(Model-View...
在压缩包文件"spring3_rest"中,可能包含了一个简单的Spring 3.0 MVC和REST的例子,你可以通过这个例子学习如何配置Spring MVC的DispatcherServlet,创建RESTful端点,处理请求和响应,以及如何使用JUnit进行测试。...
在这个“Spring3.0源码3”中,我们将深入探讨Spring 3.0的核心组件和设计理念,以及它在实际开发中的应用。 1. **依赖注入(DI, Dependency Injection)**:Spring的核心特性之一,允许对象之间的依赖关系通过配置...
9. **测试框架改进**:Spring Test模块加强了对JUnit和TestNG的支持,提供了更丰富的测试工具和上下文管理,便于进行单元测试和集成测试。 10. **Web Flow集成**:Spring Web Flow与Spring MVC的集成进一步完善,为...
以上只是Spring 3.0配置知识的一部分,实际文档中会涵盖更多细节,包括如何配置数据源、事务管理、缓存、任务调度等,以及如何使用Spring的测试框架进行单元测试和集成测试。通过深入学习和理解这些配置机制,开发者...
注解驱动的开发是Spring 3.0的一大亮点,它允许开发者通过在类和方法上使用注解来简化配置,如@Service、@Repository和@Controller,这些注解分别用于标记服务、数据访问对象和控制器组件。此外,@Autowired自动装配...
Spring 3.0提供了全面的测试支持,包括单元测试和集成测试。Spring TestContext Framework提供了诸如@ContextConfiguration、@RunWith等注解,方便测试环境的配置和管理。 总的来说,Spring 3.0的官方文档详尽地...
Struts2.1.8+Hibernate3.3+Spring3.0是经典的Java Web开发框架组合,也被称为SSH(Struts2、Spring、Hibernate)。这个环境的搭建涉及到多个步骤,涵盖了MVC(Model-View-Controller)框架、持久化框架和依赖注入...