天天看點

[Struts]使用StrutsTestCase對Action進行單元測試簡介

目前,測試驅動開發正變得越來越流行,由于“存在的就是合理的”,這種開發方式必然有其優越之處。作為一個小小程式員,對新鮮技術的追求是工作的重要動力,相信大家都有同感吧。

測試驅動開發是極限程式設計(XP)的重要組成部分,從字面上就可以看出,它是先有測試再有代碼的。這聽起來似乎有點奇怪,實際上,可以把測試用例當作需求,程式員的工作就是寫出滿足這種需求的代碼,即讓這些測試都能夠通過。在剛剛寫好測試用例的時候,由于還沒有實際代碼,是以這時運作測試的結果一定不會通過,随着代碼的增加,越來越多的測試得以通過,最後全部通過。這時,基本上可以說系統的每個功能單元都是正确的,剩下的工作就是內建測試了。而這些測試用例的使命并未結束,因為代碼會不斷修改,我們需要經常(例如每天)運作測試來檢驗目前的代碼是否能夠通過測試。很明顯,這種檢驗是完全自動化的,既快速有保證品質。

由于我已經寫了一些代碼,是以我進行的不能算是真正的測試“驅動”開發,我主要是把StrutsTestCase作為一種自動化的測試工具來用,起到保證代碼品質的作用。

舉例來說,我有一個類名為SaveTeacherAction的Action,其所在子產品名為teacher,通路路徑為/save,與他相關聯的是名為TeacherForm的ActionForm,(struts-config-teacher.xml)配置如下所示:

[Struts]使用StrutsTestCase對Action進行單元測試簡介

<action

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    attribute="teacherForm"

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    input="/form/teacher.jsp"

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    name="teacherForm"

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    path="/save"

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    scope="request"

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    type="edu.pku.cc.democenter.teacher.action.SaveTeacherAction">

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    <forward name="success" path="/list.do" redirect="true" />

[Struts]使用StrutsTestCase對Action進行單元測試簡介

</action>

[Struts]使用StrutsTestCase對Action進行單元測試簡介

SaveTeacherAction類中的execute方法如下,其中HibernateDAO是我自己寫的用來進行持久化操作的包裝類,BeauUtils是Jakarta commons包中的一個實用工具,可以在兩個Bean類型對象的相同屬性之間進行複制:

[Struts]使用StrutsTestCase對Action進行單元測試簡介

public ActionForward execute(

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    ActionMapping mapping,

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    ActionForm form,

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    HttpServletRequest request,

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    HttpServletResponse response)

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    throws Exception {

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    HibernateDAO dao=HibernateDAO.getInstance(getServlet().getServletContext());

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    TeacherForm teacherForm = (TeacherForm) form;

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    Teacher t=null;

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    if("Create".equals(teacherForm.getAction())){

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        t=new Teacher();

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    }

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    if("Edit".equals(teacherForm.getAction())){

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        t=(Teacher)dao.findByCode(Teacher.class,teacherForm.getCode());

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    BeanUtils.copyProperties(t,teacherForm);

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    dao.saveOrUpdate(t);

[Struts]使用StrutsTestCase對Action進行單元測試簡介

    return mapping.findForward("success");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

}

[Struts]使用StrutsTestCase對Action進行單元測試簡介

下面,我要寫一個測試用例來對這個Action進行測試。在Eclipse裡使用StrutsTestCase非常簡單,隻需要在工程的classpath裡包含strutstest-2.1.2.jar這個包以及junit的包就可以開始編寫了。我為這個類起名為TestSaveTeacherAction,即Action類名前加上Test字樣,所在包也與實際代碼分開,使用edu.pku.cc.democenter.test的名稱(與之對比,SaveTeacherAction的包名為edu.pku.cc.democenter.teacher.action,democenter是我們這個項目的名稱)。

現在來看一下TestSaveTeacherAction的内容:

[Struts]使用StrutsTestCase對Action進行單元測試簡介

package edu.pku.cc.democenter.test;

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

import servletunit.struts.MockStrutsTestCase;

[Struts]使用StrutsTestCase對Action進行單元測試簡介

import edu.pku.cc.democenter.teacher.form.TeacherForm;

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

public class TestTeacherAction extends MockStrutsTestCase{

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    protected void setUp() throws Exception {

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        super.setUp();

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        setConfigFile("teacher","/WEB-INF/struts-config-teacher.xml");

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    protected void tearDown() throws Exception {

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        super.tearDown();

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    public void testSaveTeacherAction_Create(){

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        setRequestPathInfo("/teacher","/save");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        TeacherForm form=makeForm();

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setAction("Create");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setCode("test.create");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        setActionForm(form);

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        actionPerform();

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        verifyForward("success");

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    public void testSaveTeacherAction_Edit(){

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setCode("test.edit");

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setAction("Edit");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setBirthDate("1979-1-10");

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

    private TeacherForm makeForm(){

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        TeacherForm form=new TeacherForm();

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setBirthDate("1979-1-1");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setCode("test.001");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setEmail("[email protected]");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setName("test");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setShortName("CS");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        form.setTel("62760000");

[Struts]使用StrutsTestCase對Action進行單元測試簡介

        return form;

[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介
[Struts]使用StrutsTestCase對Action進行單元測試簡介

使用Mock方式的測試用例都繼承servletunit.struts.MockStrutsTestCase這個類,setUp和tearDown方法分别是測試前後進行準備和善後工作的地方。要運作的測試方法都以test開頭,系統會自動調用這些方法。

由于SaveTeacherAction根據request中的action參數有兩種運作方式:Create和Edit,是以我寫了兩個test方法對它們分别進行測試。這裡要注意的是,這些test方法運作的順序是不确定的,不要認為可以先運作create的測試,再以此為基礎對剛剛create的對象進行edit,看testSaveTeacherAction_Edit方法的寫法。

我在setUp方法裡指定了子產品和對應的配置檔案名稱,如果沒有子產品可以省去這一步。在實際的testSaveTeacherAction_Create方法裡,首先用setRequestPathInfo方法指定要測試的Action的路徑和子產品,如果沒有子產品可以用一個參數的同名方法。然後構造一個ActionForm,對于我的例子就是TeacherForm,為了簡化代碼,我寫了一個makeForm方法來生成一個填好值的TeacherForm。用setActionForm将這個TeacherForm連接配接到Action,actionPerform方法通知執行Action操作。這時按照我們的設想,Action會将請求轉發到一個名為success的Forward,是以我們使用verifyForward("success")方法驗證是否進行了轉發。在這一步如果失敗,就表明此單元測試失敗,否則為成功。

testSaveTeacherAction_Edit方法與其類似,隻是要注意在這個方法裡要自己建立對象再修改,而不能使用testSaveTeacherAction_Create方法裡建立的對象,因為這兩個方法的執行順序是不确定的。

要在Eclipse裡運作這個測試也很簡單,先輕按兩下打開這個類,然後在Run菜單裡選擇Run As->JUnit Test就可以了,你會看到一個JUnit視圖,裡面有一個綠色的進度條,如果走到頭還保持綠色表示所有的測試都成功,否則會變成紅色,并在下面顯示異常的堆棧資訊。(成就感哦)

好了,今天對StrutsTestCase作了一個很簡單的介紹,我也是剛剛開始使用它,今後肯定還會遇到問題的,敬請關注後續報道。

另,相關的一些文章可以在網上找到,作為入門很好,例如:

<a href="http://plateau.sicool.com/article/tdd/strutstestcast_junit_tdd.htm">http://plateau.sicool.com/article/tdd/strutstestcast_junit_tdd.htm</a>

我的感覺,遇到問題最好先找文檔,養成習慣後不但解決問題快了,同時在看文檔的同時還可以對其加深了解,何樂而不為呢。

繼續閱讀