Cactusによるテストコードの記述方法
まずはテストしたいサーバーサイドコードに応じて、Cactusのテストケースを拡張した対応するテストクラスを作成します。拡張されるテストケースには次の3種類があります。
クラス名 | 対象となるテストケース |
ServletTestCase |
Servlet |
JspTestCase |
JSP、カスタムタグ |
FilterTestCase |
フィルタ |
上の表のテストケースクラスを継承させる形でテストケースを作成していきますが、CactusはJUnitを拡張しているだけあって、テストコードの書き方はJUnitとほとんど同じです。ただ、request
やresponse
などのHTTP特有の機能もテストできるように拡張してある点が異なります。テストはbeginXXX()
(前処理)→testXXX
(テスト)→endXXX()
(後処理)のメソッド順で行われますが、beginXXX
にはリクエスト情報を設定するためのorg.apache.cactus.WebRequest
クラスが、endXXX
には、レスポンス情報を取得するためのorg.apache.cactus.WebResponse
クラスが第1引数で唯一の引数として渡されます。なお、WebRequest
オブジェクトにはrequest
を設定するための次のようなメソッドが存在します。
メンバ名 | 概要 |
addCookie(java.lang.String theName, java.lang.String theValue) |
クッキーの追加 |
addHeader(java.lang.String theName, java.lang.String theValue) |
ヘッダーの追加 |
addParameter(java.lang.String theName, java.lang.String theValue, java.lang.String theMethod) |
(GET or POST)パラメータの追加 |
setContentType(java.lang.String theContentType) |
content-typeの追加 |
さらにWebResponse
では、response
から情報を取得するために次のようなメソッドが存在します。
メンバ名 | 概要 |
getStatusCode() |
HTTPステータスコードを取得 |
getCookie(java.lang.String theName) |
クッキーの取得 |
getInputStream() |
responseをストリームで取得 |
また、Cactusでは本来サーブレットコンテナが生成するさまざまなオブジェクトをRedirector Proxyによって暗黙オブジェクトとして生成し、テストコードで設定/取得/実行ができるようにしています。主によく使われる暗黙オブジェクトには次のようなものがあります。
対象となるテストケース | インスタンス名 | 暗黙オブジェクトクラス | 継承クラス |
すべて | request | org.apache.cactus.server .HttpServletRequestWrapper |
javax.servlet.http .HttpServletRequest |
すべて | response | javax.servlet.http .HttpServletResponse - |
|
Servlet,JSP | config | org.apache.cactus.server .ServletConfigWrapper |
javax.servlet.ServletConfig |
Servlet,JSP | session | javax.servlet.http.HttpSession - | |
JSP | pageContext | org.apache.cactus .server.PageContextWrapper |
javax.servlet.jsp.PageContext |
Filter | config | org.apache.cactus.server .FilterConfigWrapper |
javax.servlet.FilterConfig |
次に、それぞれの基底クラスを拡張した実際のテストクラスを解説します。
Servletのテストコード記述方法
Servletのテストコードの記述について解説します。具体的には一つのテストを記述した場合、以下のコードのようになります。
package to.msn.wings.cactussample; import java.io.IOException; import javax.servlet.ServletException; import org.apache.cactus.ServletTestCase; import org.apache.cactus.WebRequest; import org.apache.cactus.WebResponse; /** * Tests of the <code>HelloServlet</code> servlet class. * * @version $Id: TestHelloServlet.java 238816 2004-02-29 16:36:46Z vmassol $ */ public class TestHelloServlet extends ServletTestCase { public TestHelloServlet(String theName) { super(theName); } public void beginHello(WebRequest request){ request.addParameter("name", "ken"); } public void testHello() throws IOException,ServletException { HelloServlet servlet = new HelloServlet(); servlet.service(request, response); assertEquals("ken", request.getAttribute("name")); } public void endHello(WebResponse theResponse) throws IOException { //HTTPステータスコード-正常 assertEquals(200, theResponse.getStatusCode()); } }
1つのテストコードは、beginXXX
、testXXX
、endXXX
の3つのメソッドから構成されます。XXX
にはテストの名称を入れます。基本的にはbeginXXX
メソッドでリクエストパラメータの設定をし、testXXX
メソッドでサーブレットオブジェクトを生成して実行し、endXXX
メソッドで実行結果を確認するという流れになります。
テスト対象のServletでは、request.getParameter
で受け取った値を、request.setAttribute
で設定するという処理を行っているため、beginXXX
メソッドで設定した値をendXXX
メソッドで正しく受け取れているかというテストを行っています。
なおCactusの各テストケースクラスは、JUnitのクラスを継承しているため、assertXXX
メソッドは同一のものが使用できます。以下に簡単に表にまとめました。
メソッド名 | 概要 |
assertEquals |
2つの変数が同一のオブジェクト(またはプリミティブ値)であるかどうかを判定 |
assertTrue |
boolean値がTrueであるかどうかを判定 |
assertSame |
2つの変数が同一の参照オブジェクトであるかを判定 |
Filterのテストコード記述方法
Filterのテストコード記述方法は基本的にServletと同じです。beginXXX
、testXXX
、endXXX
の3つのメソッドで構成され、リクエストの設定、実行、結果の確認を行います。また、次のサンプルプログラムのようにtestXXX
メソッドにすべてを記述することもできます(Servletのテストコードでも同様にできます)。このテストコードでは、テスト対象のフィルタクラスを生成/実行し、characterEncoding
をUTF-8に正しく設定しているかどうかをテストしています。
package to.msn.wings.cactussample; import java.io.IOException; import javax.servlet.ServletException; import org.apache.cactus.FilterTestCase; public class TestSetEncodingFilter extends FilterTestCase { public void testEncoding()throws ServletException,IOException{ SetEncodingFilter filter = new SetEncodingFilter(); filter.init(config); filter.doFilter(request, response, filterChain); assertEquals("UTF-8",request.getCharacterEncoding()); } }
JSP、カスタムタグのテストコード記述方法
JSP、カスタムタグのテストコードについても、記述方法は基本的にServlet、Filterと同じです。JSPはrequest.setAttribute()
した後に、暗黙オブジェクトpageContext
のinclude
メソッドでJSPを読み込む処理を行います。読み込んだ結果はresponse
に格納されるので、response.getText
で、指定されたHTML
タグが存在するかを検証しています。
package to.msn.wings.cactussample; import org.apache.cactus.JspTestCase; import org.apache.cactus.WebResponse; public class TestHelloJSP extends JspTestCase { public TestHelloJSP(String theName) { super(theName); } public void testHelloJSP() throws Exception { request.setAttribute("name","ken"); this.pageContext.include("/hello.jsp"); } public void endHelloJSP(WebResponse res) throws Exception { int index = res.getText().indexOf( "<div id=\"hello\">Hello ken</div>"); assertEquals(false,index < 0); } }
また、以下のカスタムタグのテストコードでは、request.setAttribute()
した後に、Hello
タグのインスタンスのdoStartTag()
を呼び出します。その後、その結果をresponse.getText
で受け取って正しい値を生成しているか検証しています。
package to.msn.wings.cactussample; import javax.servlet.jsp.tagext.Tag; import org.apache.cactus.JspTestCase; import org.apache.cactus.WebResponse; public class TestHelloTag extends JspTestCase { public TestHelloTag(String theName) { super(theName); } private HelloTag tag; public void testHelloTag() throws Exception { this.tag = new HelloTag(); this.tag.setPageContext(this.pageContext); this.request.setAttribute("name","ken"); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); } public void endHelloTag(WebResponse theResponse) { assertEquals(theResponse.getText(), "Hello ken"); } }
テストの実行
テストの実行にはいくつかの方法が存在します。EclipseにCactusのpluginであるCactusRunnerを入れてテストする方法や、antから実行する方法などです。今回はantでテストを実行し、テスト結果をコンソールから確認する方法と、ブラウザ上で確認する方法の2パターンを解説します。antでテストを実行するには「ant test」と実行してください。これで、次のようにテスト結果をコンソールに出力してくれます。
また、テストを実行した際にXMLとしてテスト結果を出力するので、それをブラウザ上で確認することもできます。確認する画面は次のようなものになります。
このテストの実行結果をXMLとして出力する処理は、「build.xml」の<junitreport>
に記述されています。大量のテスト結果を見やすく確認したい場合には便利です。出力先を換えるには、<junitreport>
のtodir
を変更すればOKです。
まとめ
本稿では、Cactusを利用したWebアプリケーションの自動テストについて解説しました。Junitを利用したことがあっても、Cactusまでは導入していない開発者の方は多いのではないでしょうか? 最初の設定がやや面倒ではありますが、基本的にはJUnitの拡張であり、JUnitに慣れてさえいれば、それほど学習コストもかかりません。最近では、ブラウザを介してJavaScriptでViewのテストをするSeleniumなど、さまざまなWebアプリケーションテストフレームワーク、ライブラリが出てきていますが、まずJUnitに慣れている方は、Cactusから導入してみてはいかがでしょうか? 本稿が導入のお役に立てれば幸いです。