spring-test單元測試(二)-進行struts action的請求單元測試
單元測試雖不強求,但你一旦養成習慣,你會愛上它。另外我們保證程式碼質量的兩個很重要的手段,一個是頭(單元測試)一個是尾(codereview)。那麼我們最常用的單元測試就是通過junit來進行,spring-test框架很好的集成了junit來進行這項工作,比如測試dao,測試service(參見另外一篇文章)。
同時我們還會有這樣的需求我不想啟動tomcat來測試action(struts)或者controller(springmvc)。好了,我們還是用咱們熟悉的工具spring-test。
先介紹如何在struts環境中,不啟動tomcat來測試action請求,我們測試struts的action需要用到struts2-junit-plugin這個外掛。
一、 準備工作
引入下面兩個maven座標第一個是junit的struts外掛,第二個是作為mock使用(模擬物件的行為),第三個spring-test。
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-junit-plugin</artifactId>
<version>2.3.29</version>
</dependency>
<dependency> |
|
<groupId>org.easymock</groupId> |
<artifactId>easymock</artifactId> |
|
<version>3.4</version> |
</dependency> |
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
<scope>test</scope>
</dependency>
二、 建立一系列用到的測試檔案
全部放入test檔案目錄(標準,所有測試檔案都要歸併在test資料夾下面)
整體描述,採用原始碼+註釋的說明
ActionTest.java檔案測試action的主類
package com.jd.pop.odp.web.action;
import com.jd.pop.odp.service.TestService;
import com.opensymphony.xwork2.ActionProxy;
import org.apache.struts2.StrutsSpringJUnit4TestCase;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Created by wangxindong on 2016/11/21.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:/spring/spring-config-test-service.xml"})
/*這裡只需要載入使用到的檔案,不需要測試的檔案不要載入(注意),我們現在是測試action,由於struts啟動會預設載入三個檔案,分別是struts-default.xml,struts-plugin.xml,struts.xml
如果我們要單獨對某一個struts檔案做測試,在struts.xml檔案中單獨引用即可,比如<includefile="struts/struts-test.xml"/>*/
public class ActionTest extendsStrutsSpringJUnit4TestCase<VenderTestAction> {
private TestService testService;
@Before
public void setUp() throws Exception{
super.setUp();//必須要有,初始化用,參見UML圖
//模擬request,response
request = newMockHttpServletRequest();
request.setCharacterEncoding("UTF-8");
response = newMockHttpServletResponse();
//建立mock物件
testService = EasyMock.createMock(TestService.class);
}
@Test
public void testQuery() throws Exception{
ActionProxy proxy = null;
VenderTestAction venderTestAction =null;
request.setParameter("oplogId", "1234567");
proxy =getActionProxy("/vendertest/oplog_query.action");
venderTestAction =(VenderTestAction)proxy.getAction();
//模擬物件的行為
//記錄mock物件期望的行為
EasyMock.expect(testService.queryResult()).andReturn("test-mock");//我們期望返回test-mock,則會切斷正常的呼叫
//進入replay階段
EasyMock.replay(testService);
venderTestAction.setTestService(testService);//這裡必須要用mock之後的物件,才能達到mock模擬物件行為的作用,比如我們這裡讓queryResult這個方法返回”test-mock”
String result = proxy.execute();//必須要有,否則被測試的action裡面的request值為null
// String queryResult = test.query();
}
}
VenderTestAction.java被測試的action
package com.jd.pop.odp.web.action;
import com.jd.pop.odp.service.TestService;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by wangxindong on 2016/11/21.
*/
public class VenderTestAction extends ActionSupport implementsServletRequestAware, ServletResponseAware {
private HttpServletRequest request;
private HttpServletResponse response;
@Resource
private TestService testService;
public String query(){
System.out.println("comehere venderTestAction :"+request.getParameter("oplogId"));
System.out.println("comehere venderTestAction2");
String result =testService.queryResult();
System.out.println("result:"+result);
return SUCCESS;
}
@Override
public voidsetServletRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public voidsetServletResponse(HttpServletResponse response) {
this.response = response;
}
public voidsetTestService(TestService testService) {
this.testService = testService;
}
}
struts-test.xml檔案
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache SoftwareFoundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<packagename="vendertest" extends="struts-default"namespace="/vendertest">
<actionname="oplog_*" method="{1}"class="com.jd.pop.odp.web.action.VenderTestAction">
<resultname="success">/WEB-INF/vm/oplog/vender/logList.vm</result>
</action>
</package>
</struts>
spring-config-test-service.xml業務bean的配置檔案(當然你也可以用註解的方式加入到容器環境中)
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName">
<bean id="testService"class="com.jd.pop.odp.service.impl.TestServiceImpl"/>
</beans>
TestService.java業務類介面
package com.jd.pop.odp.service;
/**
* Created by wangxindong on 2016/11/23.
*/
public interface TestService {
public String queryResult();
}
TestServiceImpl.java業務類實現
package com.jd.pop.odp.service.impl;
import com.jd.pop.odp.service.TestService;
/**
* Created by wangxindong on 2016/11/23.
*/
public class TestServiceImpl implements TestService {
@Override
public String queryResult() {
return "test-reslut";//注意這裡返回的是 test-result這個值,我們在假設這個依賴不//好使的時候我們在mock的時候,是返回的另外一個值
}
}
struts.xml檔案
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache SoftwareFoundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constantname="struts.enable.DynamicMethodInvocation"value="false"/>
<constantname="struts.devMode" value="false"/>
<constantname="struts.objectFactory" value="spring"/>
<include file="struts/struts-test.xml"/>
</struts>
三、逐一說明具體用法
1、struts啟動的時候會預設載入struts-default.xml,struts-plugin.xml,struts.xml這三個檔案,因此如果如果我們要單獨對某一個struts檔案做測試,在struts.xml檔案中單獨引用即可,比如<includefile="struts/struts-test.xml"/>
2、super.setUp();//必須要有,初始化用,參見UML圖,它是用來初始化比如容器,準備檔案一系列工作
3、Mock的使用,我們呼叫第三方的介面,比如jsf等,如果很慢,或者他們壓根測試環境就壞掉了,這個時候mock就非常強大了。比如我們這裡的使用,來模擬TestService的queryResult()返回情況。
(1)//建立mock物件
testService = EasyMock.createMock(TestService.class);
(2)//記錄mock物件期望的行為
EasyMock.expect(testService.queryResult()).andReturn("test-mock");//我們期望返回test-mock,則會切斷正常的呼叫
(3)//進入replay階段
EasyMock.replay(testService);
總結:優點1-不用啟動tomcat即可測試action請求,提高工作效率 2-採用mock,在第三方介面壞掉的情況下,仍然不影響我們測試(如果我們不用mock,另外一種方式就是stub(樁)打樁的方式,另外寫一個實現類實現TestService,這樣工作量就會比較大,mock這種模擬物件行為的方式非常優秀)