1. 程式人生 > >spring-test單元測試(二)-進行struts action的請求單元測試

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.xmlstruts-plugin.xmlstruts.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就非常強大了。比如我們這裡的使用,來模擬TestServicequeryResult()返回情況。

(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這種模擬物件行為的方式非常優秀