2008年7月29日 星期二

[Struts] StrutsTestCase for JUnit

Introduction

對於寫過test case 的 programmer 來說,JUnit 應該是不陌生,JUnit 是被大家公認用來執行java測試最好的framework,但是對於像Struts這種以MVC為宗旨的framework,我們又該如何去執行測試呢?StrutsTestCase for JUnit[1] 就是一個用來達成我們目的的solution。從字面上就可以了解,StrutsTestCase其實就是將JUnit延伸到Struts framework可以使用的library。所以,大致上對於測試的方式是大同小異的,不過對於StrutsTestCase[1]來說,還是有一些不一樣之處。

下圖一是官方網站的簡介,此網站對於StrutsTestCase[1]有很詳細的說明。

clip_image003

圖一 官方網站的說明

圖一中的紅圈處就可以下載該library。點選後就會進入SourceForge.net的網站,如下圖二。

clip_image005

圖二 SourceForge.net的下載點

接個點選Download字樣,進入如下圖三的畫面。

clip_image007

圖三 SourceForge.net的下載點(2)

畫面中請下載您所需要的版本,通常是選擇下載最新版本為主,圖中最後一個載點是在檔名後方加上 -src代表是原始碼的版本,若您有需要訂做自己適用的StrutsTestCase,您也可以下載原始碼版本。

下載完的壓縮檔案解開後的資料夾中會包含一個strutstest-x.jar(其中x會依照您所下載的版本不同而有所改變)。若是一般的 Java Application 要使用,請設定 classpath 位置;若是需要在 Web Server 上面的 Web Application 使用,請放置該 Web Application 的 WEB-INF / lib 之下。

Example

首先假設您有一個action如下:

public class LoginAction extends Action {

    public ActionForward excute(...) {

        String username = ((LoginForm)form).getUsername();

        String password = ((LoginForm)form).getPassword();

        String role = “user”;

        if (username.equals(“adm”) && password.equals(“test”)) {

            role = “adm”;

        }

        request.getSession().setAttribute(“role”,role);

        request.getSession().setAttribute(“username”,username);

    }

}

上述程式碼中,我們假設您已經有一個LoginForm class。上述的action您在struts-config.xml中設定如下:

<action path=”/login” type=”LoginAction” />

接下來您就可以根據您的action來開發strutstestcases測試,開發strutstestcase步驟如下:

(1) 您必須建立新的class,我們命名為LoginActionTest並且extends MockStrutsTestCase:

public class LoginActionTest extends MockStrutsTestCase {

}

(2) 如果您是在 eclipse 環境下執行測試,請您務必加入以下的程式碼:

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”)); //註一

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

}

註一:其中WebContent要根據您在eclipse中建立的資料夾而定,依照我所設定的資料夾如下圖四,所以我們採用WebContent:

clip_image013

圖四 Eclipse專案的目錄結構

(3) 接著我們就要開始來正式的撰寫我們的test case,所有的test case method都必須以test開頭,例如:testLogin。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {}

}

(4) 有了test case method,我們就要開始撰寫內容了。首先,我們要先告知strutstestcase我們要測試的路徑,也就是瀏覽器如何存取該action的方法,不過,我們只需要設定在struts-config.xml中的路徑即可,無須增加IP位址,因為MockStrutsTestCase是屬於Mock Test測試(也就是非in-container測試,所謂的container就是由tomcat這類的server來啟動,所以in-container就是會啟動tomcat server來進行測試,Mock Test就是另一種不用啟動tomcat server的離線測試),先前我們已經將LoginAction class在struts-config.xml中設定的路徑為/login,所以我們可以透過MockStrutsTestCase所提供的setRequestPathInfo() method來設定action的存取位置。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

    }

}

NOTE: 呼叫superclass的methods時,可以使用super關鍵字,本人建議所有呼叫superclass的methods時,都加上super關鍵字,以方便未來觀看程式碼時就可以一目了然,另外,若是呼叫同一個method時,請您也加上this來方便日後的維護。這並沒有硬性的規定,所以的關鍵字都不加上去,程式碼依舊可以執行,這只是習慣性的問題而已。

(5) 再來就是告知該action我們要傳入的資料,此資料就是模擬使用者會傳入哪些資料給action。切記,雖然我們的action是接收一個ActionForm物件,不過在MockStrutsTestCase中是用類似URL GET method(../login.do?username=adm&…)的方式給予。我們並不能給予ActionForm物件。所以我們要呼叫MockStrutsTestCase的addRequestParameter() method,並將我們要給予的參數名稱與參數值。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

    }

}

(6) 設定好路徑與參數後,我們就要告知MockStrutsTestCase,該測試可以啟動了,所以我們就呼叫他的actionPerform() method來正式的執行該action。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

        super.actionPerform();

    }

}

(7) Action執行完後,我們就可以針對action執行後的結果作測試,因為我們的action是將結果儲存在session中,所以我們就要從session中取出結果,並且呼叫JUnit的測試method來檢驗結果。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

        super.actionPerform();

        String role = super.getSession().getAttribute(“role”);

        super.assertEquals(role,”adm”);

    }

}

NOTE:若action是將結果儲存在request中,您就要改呼叫super.getRequest() method來進行測試。

References

[1] StrutsTestCase官方網站 http://strutstestcase.sourceforge.net/