Struts2 单元测试 —— Struts2-JUnit-Plugin 踩坑记

版权声明:大家好,我是笨笨,笨笨的笨,笨笨的笨,转载请注明出处,谢谢! https://blog.csdn.net/jx520/article/details/89646441

第一添加依赖

        <!-- JUnit 输出日志用 -->
        <dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<!-- JUnit 输出日志用 -->
        <dependency>
		  <groupId>com.github.stefanbirkner</groupId>
		  <artifactId>system-rules</artifactId>
		  <version>1.16.0</version>
		  <scope>test</scope>
		</dependency>
		<!-- Struts action 单元测试用 -->
		<dependency>
		    <groupId>org.apache.struts</groupId>
		    <artifactId>struts2-junit-plugin</artifactId>
		    <version>${struts.version}</version>
		    <scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
			<scope>test</scope>
		</dependency>

指定 spring 配置文件位置

这个不算坑。如果你的配置文件不在默认的位置,设置一下就好了。
/jerry-demo/src/main/resources/config/applicationContext.xml

    @Override
    protected String[] getContextLocations() {
         //重设 Spring XML路径
         return new String[] { "classpath*:config/applicationContext.xml" };
    }

坑一【request,response 为 null】

因为我给所有 Action 加了个父类 BaseAction,并在里面定义了 request, response 方便子类。

public class BaseAction extends ActionSupport {
	protected HttpServletRequest request = ServletActionContext.getRequest();
	protected HttpServletResponse response = ServletActionContext.getResponse();
	...
}

但是 org.apache.struts2.StrutsTestCase#getActionProxy(String uri)} 先创建 ActionProxy 后注入 request, response 导致我所有的 Actionrequest, response 都变成 null 了。所以我要在它访问前手动注入一下。

    @Override
    protected void setUp() throws Exception {
        super.setUp();
    	ServletActionContext.setServletContext(servletContext);
    	ServletActionContext.setRequest(request);
    	ServletActionContext.setResponse(response);
    }

当然除了上面这点,还有些常用的功能也要加上,所以最后面我们会整理一下。

坑二【struts.xml 必须放在 classpath 下】

它默认到 /jerry-demo/src/main/resources/struts.xml 下找 struts 配置文件。你不放这里它就给你 404

Dispatcher#sendError: 404

如果你的配置文件在/jerry-demo/src/main/resources/strutsConfig/struts.xml不方便移过来,那就创建一个/jerry-demo/src/main/resources/struts.xml引用它吧。

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts> 
	<include file="strutsConfig/struts.xml"></include>
</struts>


完整的代码例子

日志工具类

package com.jerry.tools;

import org.junit.Rule;
import org.junit.contrib.java.lang.system.SystemErrRule;
import org.junit.contrib.java.lang.system.SystemOutRule;

/**
 * JUnit 日志输出工具类
 */
public class JUnitLogTool {
	// 正确输出
	@Rule
	protected final static SystemOutRule logOut = new SystemOutRule();

	// 错误输出
	@Rule
	protected final static SystemErrRule logErr = new SystemErrRule();

	/**
	 * 用于测试中,向控制台输出信息
	 * @author jerryjin
	 */
	public static class Log {
		public void out(String msg) {
			System.out.println("----------------------log.out begin-------------------------------");
			System.out.println(msg);
			System.out.println("-----------------------log.out end--------------------------------");
			logOut.getLog();
		}

		public void err(String msg) {
			System.out.println("----------------------log.err begin-------------------------------");
			System.err.println(msg);
			System.out.println("-----------------------log.err end--------------------------------");
			logErr.getLog();
		}
	}
	
	public String getMsg(String msg, Object... args) {
		return String.format(msg, args);
	}
}

断言工具类

根据具体情况,添加几个方法。

package com.jerry.tools;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import java.util.Map;
import com.jerry.dto.IBaseDTO;

/**
 * Assert 工具类
 */
public class AssertTool {
	
	/**
	 * 期望 resultMap 中 msg 的值为 success
	 * @param resultMap 待验证的结果map
	 */
	public static void assertMapMsg(Map<String, Object> resultMap) {
		assertMapMsg(resultMap, "success");
	}
	
	/**
	 * 期望 resultMap 中 msg 的值为 expectedMsg
	 * @param resultMap		待验证的结果map
	 * @param expectedMsg	待验证的结果值。通常是 "success"
	 */
	public static void assertMapMsg(Map<String, Object> resultMap, String expectedMsg) {
		assertEquals(expectedMsg, (String) resultMap.get("msg"));
	}
	
	/**
	 * 期望触发一个异常
	 * @param dto
	 * @param message
	 */
	public static void assertException(IBaseDTO<?, ?> dto, String message ){
		try {
			dto.validate();
		} catch (Exception e) {
			assertTrue(e instanceof IllegalArgumentException);
			assertEquals(message, e.getMessage());
			return ;
		}
		assertTrue("期望的异常: " + message + "。未触发", false);
	}
}

测试基类【带日志输出】

package com.jerry;

import com.jerry.tools.JUnitLogTool;
import junit.framework.TestCase;

/**
 * {@linkplain JUnit} 单元测试基类
 * <br>支持 JUnit 中日志输出
 */
public class BaseLogTest extends TestCase {
	// JUnit日志输出工具类
	protected static com.jerry.tools.JUnitLogTool.Log log = new JUnitLogTool.Log();
}

测试基类【带日志输出 + Spring支持】

package com.jerry;

import java.util.Map;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jerry.dto.IBaseDTO;
import com.jerry.tools.JUnitLogTool;
import junit.framework.TestCase;

/**
 * {@linkplain JUnit} + {@linkplain Spring} 单元测试基类
 * <br>支持 JUnit 中日志输出
 */
public class BaseTest extends TestCase {
	// 初始化上下文;
	protected static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "config/applicationContext.xml");
	// JUnit日志输出工具类
	protected static com.jerry.tools.JUnitLogTool.Log log = new JUnitLogTool.Log();
	
	public <T> T getBean(Class<T> requiredType) {
		return context.getBean(requiredType);
	}

	public Object getBean(String requiredType) {
		return context.getBean(requiredType);
	}
	
	protected void assertResultMap(Map<String, Object> resultMap) {
		assertEquals("success", (String) resultMap.get("msg"));
		log.out(resultMap.toString());
	}
	
	public void assertException(IBaseDTO<?, ?> dto, String message ){
		try {
			dto.validate();
		} catch (Exception e) {
			assertTrue(e instanceof IllegalArgumentException);
			assertEquals(message, e.getMessage());
			return ;
		}
		assertTrue("期望的异常: " + message + "。未触发", false);
	}
}

测试基类【带日志输出 + Spring支持 + Struts2支持】

package com.jerry;

import javax.swing.Spring;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsSpringTestCase;
import com.jerry.tools.JUnitLogTool;

/**
 * {@linkplain Struts2} + {@linkplain JUnit} + {@linkplain Spring} 单元测试基类
 * <br>支持 JUnit 中日志输出
 */
public class BaseStruts2Test extends StrutsSpringTestCase {
	// ----------------------------------- struts junit spring 开始 --------------------------------------------
    @Override
    protected String[] getContextLocations() {
         //重设 Spring XML路径
         return new String[] { "classpath*:config/applicationContext.xml" };
    }
    
    /**
     * 从 Spring 容器获取 bean
     * @param clazz 目标类型
     * @return
     */
    public <T> T getBean(Class<T> clazz) {
		return applicationContext.getBean(clazz);
	}
 	/**
 	 * 从 Spring 容器获取 bean
 	 * @param className 目标类名
 	 * @return
 	 */
	public Object getBean(String className) {
		return applicationContext.getBean(className);
	}    

    /**
     * 因为我给所有 Action  加了个父类 BaseAction,并在里面定义了 request, response 但是 
     * {@link org.apache.struts2.StrutsTestCase#getActionProxy(String uri)} 先创建 ActionProxy 后注入 request, response
     * 导致我所有的 Action 中  request, response 都变成 null 了。所以要在这里手动注入一下
     */
    @Override
    protected void setUp() throws Exception {
        super.setUp();
    	ServletActionContext.setServletContext(servletContext);
    	ServletActionContext.setRequest(request);
    	ServletActionContext.setResponse(response);
    }
	// ----------------------------------- struts junit spring 结束 --------------------------------------------
    
	// ----------------------------------- log 开始 --------------------------------------------
	// JUnit日志输出工具
	protected static com.jerry.tools.JUnitLogTool.Log log = new JUnitLogTool.Log();
	// ----------------------------------- log 结束 --------------------------------------------
}

测试用例

如果上面已经执行这,这里再执行, resultJson 里就会两次执行的结果
在同一个用例中,如果多次发请求,executeAction 取返的结果也是多次的叠加。

public class MoveTicketJsonTest extends BaseStruts2Test {
	private IMoveTicketService moveTicketService = null;

	protected void setUp() throws Exception {
		super.setUp();
		// 这里用到 Service 主要是取点数据方便测试。作为请求的参数。
		moveTicketService = getBean(IMoveTicketService.class);
	}
	
	public void testGetTicke() throws Exception {
		// -------------------------- 准备请示参数 ----------------------------
		String id = "666";
		String sign = JerryCrypt.sign(id+teleportation);// 签名
		
		// ---------------------------- 模拟请求  ----------------------------
        //设置 请求参数
        request.setParameter("id", id);
        request.setParameter("sign", sign);

        //获取要测试Action
        ActionProxy proxy = getActionProxy("/json/get_Ticke.action");
        MoveTickeJson  action = (MoveTickeJson ) proxy.getAction();
        
        //执行 Action 并获取 return 结果  (success)
        String result = proxy.execute();
        assertEquals("success", result);
        
        // ------------------------- 验证请求结果验证  --------------------------
		// dataMap 是自己在控制器中定义的保存结果的map
        Map<String, Object> dataMap = action.getDataMap();
        AssertTool.assertMapMsg(dataMap);
        
        log.out(dataMap.toString());
	}


	public void testGetDetailTicke() throws Exception {
        //设置 请求参数
        request.setParameter("id", "65");
		// 执行 executeAction 得到的是接口返回的 JSON 数据
        String resultJson = executeAction("/json/detail_Ticke.action");
        JSONObject json = JSONObject.parseObject(resultJson);
        assertEquals("success", json.getString("status"));
        
        log.out(resultJson);
	}
}

猜你喜欢

转载自blog.csdn.net/jx520/article/details/89646441