雖 然JSP會轉譯為Servlet,但所謂的對JSP測試,基本上並非對轉譯後的Servlet進行測試,因為要對JSP進行特定的方法呼叫有點麻煩,另一 方 面,在 Model 2 架構中,JSP是擔任視圖呈現的職責,對JSP進行測試,通常是指針對沒有Scriptlet,只有標籤的JSP頁面進行測試,測試內容通常會是傳回的頁 面結果。
(對Scriptlet的測試技術也是可行的,可以將結果儲存在request、session中,然後在測試案例中取出進行斷言,但原則上並不鼓勵在 JSP中撰寫Scriptlet。)
假設有以下的JSP網頁:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>新增書籤</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <c:if test="\${requestScope.errors != null}">
            <h1>新增書籤失敗</h1>
            <ul style="color: rgb(255, 0, 0);">
                <c:forEach var="error" items="\${requestScope.errors}">
                    <li>\${error}</li>
                </c:forEach>
            </ul>
        </c:if>
        <form method="post" action="add.do">
            網址 http:// <input name="url" value="\${param.url}"><br>
            網頁名稱:<input name="title" value="\${param.title}"><br>
            分  類:<select name="category">
                <c:forEach var="category"
                    items="\${applicationScope.bookmarkService.categories}">
                    <option value="\${category}">\${category}</option>
                </c:forEach>
            </select>
            新增分類:<input type="text" name="newCategory" value=""><br>
            <input value="送出" type="submit"><br>
        </form>
    </body>
</html>
若對這個JSP頁面打算測試錯誤訊息的顯示、請求參數的回填與分類選單的顯示是否正確,可以如下:
package test.cc.openhome;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import org.apache.cactus.ServletTestCase;
import org.apache.cactus.WebRequest;
import org.apache.cactus.WebResponse;
public class AddJSPTest extends ServletTestCase {
    static {
        System.setProperty(
                "cactus.contextURL", "http://localhost:8080/CactusExample");
    }
    // 測試沒有錯誤時的狀態,也就是第一次造訪JSP頁面時
    public void testNoError() throws Exception {
        request.getRequestDispatcher("add.jsp").forward(request, response);
    }
    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);
        request.getRequestDispatcher("add.jsp").forward(request, response);
    }
    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 編碼
        // WebRequest 底層使用 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");
        request.getRequestDispatcher("add.jsp").forward(request, response);
    }
    public void endParameters(WebResponse resp) throws Exception {
        String html = getContent(resp);
        assertTrue(html.contains("http://test"));
        assertTrue(html.contains("測試"));
    }
    
    // 測試分類顯示
    public void testCategories() throws Exception {
        config.getServletContext().setAttribute(
                "bookmarkService", new BookmarkService());
        request.getRequestDispatcher("add.jsp").forward(request, response);
    }
    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();
    }
}
最主要的,是在取得容器提供的相關物件後,設定好JSP顯示內容時所需的相關資料,再轉發給JSP,之後JSP呈現結果後,使用WebRequest取得 相關的資料,並斷言預期的資料是否出現等。

