測試 JSP


雖 然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">
網址&nbsp;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取得 相關的資料,並斷言預期的資料是否出現等。