在 測試JSP時,除了繼承ServletTestCase之 外,你還可以選擇繼承JspTestCase, 這方便你使用JSP的隱含物件(Implicit object)來進行相關測試。例如 測試 JSP 中的測試,也可以改為以下:
package test.cc.openhome;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import org.apache.cactus.JspTestCase;
import org.apache.cactus.WebRequest;
import org.apache.cactus.WebResponse;
public class AddJSPTest extends JspTestCase {
    static {
        System.setProperty(
                "cactus.contextURL", "http://localhost:8080/CactusExample");
    }
    // 測試沒有錯誤時的狀態,也就是第一次造訪JSP頁面時
    public void testNoError() throws Exception {
        pageContext.forward("add.jsp");
    }
    public void endNoError(WebResponse resp) throws Exception {
        String html = getContent(resp);
        assertTrue(!html.contains("<h1>新增書籤失敗</h1>"));
    }
    
    // 測試表單驗證失敗,回到JSP頁面時
    public void testErrors() throws Exception {
        List<String> errors = Arrays.asList("錯誤一", "錯誤二", "錯誤三");
        request.setAttribute("errors", errors);
        pageContext.forward("add.jsp");
    }
    public void endErrors(WebResponse resp) throws Exception {
        String html = getContent(resp);
        assertTrue(html.contains("<h1>新增書籤失敗</h1>"));
        assertTrue(html.contains("<li>錯誤一</li>"));
        assertTrue(html.contains("<li>錯誤二</li>"));
        assertTrue(html.contains("<li>錯誤三</li>"));
    }
    
    // 測試表單驗證失敗,回到JSP頁面時測試請求參數回填
    public void beginParameters(WebRequest req) throws Exception {
        req.addParameter("url", "http://test");
        // 客戶端是 UTF-8 編碼,Tomcat 預設使用 ISO-8859-1 處理請求參數
        req.addParameter("title", 
                new String("測試".getBytes("UTF-8"), "ISO-8859-1"), "POST");
        
    } 
    public void testParameters() throws Exception {
        // 指定使用 UTF-8 處理請求參數
        request.setCharacterEncoding("UTF-8");
        pageContext.forward("add.jsp");
    }
    public void endParameters(WebResponse resp) throws Exception {
        String html = getContent(resp);
        assertTrue(html.contains("http://test"));
        assertTrue(html.contains("測試"));
    }
    
    // 測試分類顯示
    public void testCategories() throws Exception {
        pageContext.setAttribute("bookmarkService", 
                new BookmarkService(), pageContext.APPLICATION_SCOPE);
        pageContext.forward("add.jsp");
    }
    public void endCategories(WebResponse resp) throws Exception {
        String html = getContent(resp);
        assertTrue(html.contains("<option value=\"分類一\">分類一</option>"));
        assertTrue(html.contains("<option value=\"分類二\">分類二</option>"));
        assertTrue(html.contains("<option value=\"分類三\">分類三</option>"));
    }
    // 伺服端用UTF-8傳回
    private String getContent(WebResponse resp) throws Exception {
        InputStream input = resp.getInputStream();
        StringWriter writer = new StringWriter();
        byte[] data = new byte[2048];
        int length = -1;
        while((length = input.read(data)) != -1) {
            writer.write(new String(data, 0, length, "UTF-8"));
        }
        input.close();
        writer.close();
        return writer.toString();
    }
}
JspTestCase預 設的Redirect proxy網址是/JspRedirector, 你要將Cactus提供的jspRedirector.jsp複 製至Web應用程式中,並在web.xml中如下設定:
...
<servlet>
<servlet-name>JspRedirector</servlet-name>
<jsp-file>/jspRedirector.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>JspRedirector</servlet-name>
<url-pattern>/JspRedirector</url-pattern>
</servlet-mapping>
...
      
      <servlet>
<servlet-name>JspRedirector</servlet-name>
<jsp-file>/jspRedirector.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>JspRedirector</servlet-name>
<url-pattern>/JspRedirector</url-pattern>
</servlet-mapping>
...
使用JspTestCase也 可以測試Taglib,例如在 處 理本體執行結果 中,測試ToUpperCaseTag需要 PageContext與BodyContent物件,雖然JspTestCase不直接提供BodyContent,但可以呼叫 pageContext.pushBody()來取得BodyContent。例如:
package test.cc.openhome;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.Tag;
import org.apache.cactus.JspTestCase;
import cc.openhome.ToUpperCaseTag;
public class ToUpperCaseTagTest extends JspTestCase {
    static {
        System.setProperty(
                "cactus.contextURL", "http://localhost:8080/CactusExample");
    }
    public void testDoEndTag() throws Exception {
        ToUpperCaseTag toUpperCaseTag = new ToUpperCaseTag();
        toUpperCaseTag.setPageContext(pageContext);
        // 內層標籤執行後的輸出結果
        BodyContent innerBodyContent = pageContext.pushBody();
        innerBodyContent.append("test");
        toUpperCaseTag.setBodyContent(innerBodyContent);
        
        // ToUpperCaseTag 的 doEndTag() 中,pageContext.getOut() 取得的物件
        BodyContent toUpperCaseBodyOut = pageContext.pushBody();
        
        assertEquals(Tag.EVAL_PAGE, toUpperCaseTag.doEndTag());
        assertEquals("TEST", toUpperCaseBodyOut.getString());
    }
}
由於Taglib擁有更多的生命周期狀態,這些本來都會是由容器維護,相對來說,測試Taglib必須了解容器作了哪些事,並在測試案例中加以模擬,必要 時,觀察JSP轉譯後的Servlet,了解容器對Taglib作了哪些處理,會有助於了解如何進行Taglib的測試。

