給servlet寫單元測試的總結收藏
servlet的測試一般來說需要容器的支持,不是像通常的java類的junit測試一樣簡單,
下面通過對HelloWorld代碼的測試闡述了幾種servlet測試方法。
被測試的HelloWorld類的代碼如下:
/**
* 被測試的servlet
*/
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.cactus.WebRequest;
import org.apache.cactus.server.HttpServletRequestWrapper;
public class HelloWorld extends HttpServlet{
public void saveToSession(HttpServletRequest request) {
request.getSession().setAttribute("testAttribute",request.getParameter("testparam"));
}
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{
String username=request.getParameter("username");
response.getWriter().write(username+":Hello World!");
}
public boolean authenticate(){
return true;
}
}
以HelloWorld為例,我總結了Servlet的多種測試方法如下:
一.使用HttpUnit測試
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.servletunit.InvocationContext;
import com.meterware.servletunit.ServletRunner;
import com.meterware.servletunit.ServletUnitClient;
import junit.framework.Assert;
import junit.framework.TestCase;
public class HttpUnitTestHelloWorld extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testHelloWorld() {
try {
// 創建Servlet的運行環境
ServletRunner sr = new ServletRunner();
// 向環境中注冊Servlet
sr.registerServlet("HelloWorld", HelloWorld.class.getName());
// 創建訪問Servlet的客戶端
ServletUnitClient sc = sr.newClient();
// 發送請求
WebRequest request = new GetMethodWebRequest("http://localhost/HelloWorld");
request.setParameter("username", "testuser");
InvocationContext ic = sc.newInvocation(request);
HelloWorld is = (HelloWorld) ic.getServlet();
// 測試servlet的某個方法
Assert.assertTrue(is.authenticate());
// 獲得模擬服務器的信息
WebResponse response = sc.getResponse(request);
// 斷言
Assert.assertTrue(response.getText().equals("testuser:Hello World!"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
上述例子其實是junit的一個測試例子,在其中使用了httpunit模擬的servlet環境,使用上述方法測試
servlet可以脫離容器,容易把該測試寫入ant或maven腳本,讓測試進行。
httpunit網址:http://httpunit.sourceforge.net/
使用該種方法測試的弱點就是:如果要使用request(response)的setCharercterEncoding方法時,測試會出現一些問題,
而且httpunit在測試servlet行為時,采用的是完全模擬瀏覽器,有時測試比較難寫。
二 使用cactus測試
/**
* cactus測試servlet的例子
* 必須要有tomcat的支持
*
*/
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.cactus.ServletTestCase;
import org.apache.cactus.WebRequest;
import org.apache.cactus.WebResponse;
public class CactusHelloWorld extends ServletTestCase{
HelloWorld servlet;
public CactusHelloWorld(String theName) {
super(theName);
}
protected void setUp() throws Exception {
super.setUp();
servlet = new HelloWorld();
}
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* 測試方法測試參數在此設置
*
* @param webrequest
*/
public void beginSaveToSessionOK(WebRequest request) {
request.addParameter("testparam", "it works!");
}
/**
* 測試方法測試參數在此設置
*
* @param webrequest
*/
public void beginDoGet(WebRequest request) {
request.addParameter("username", "testuser");
}
/**
* 調用servlet的測試方法
*
*/
public void testSaveToSessionOK() {
servlet.saveToSession(request);
assertEquals("it works!", session.getAttribute("testAttribute"));
}
public void testDoGet() {
try {
servlet.doGet(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 此方法可以判斷測試方法的輸出,會傳遞測試方法的reponse給end***,并且格式化為cactus
* 的WebResponse或者可以跟httpunit集成,格式化為httpunit的response
*
* @param response
*/
public void endDoGet(WebResponse response) {
String content;
content = response.getText();
assertEquals("testuser:Hello World!", content);
}
}
cactus具備豐富靈活的測試功能,如要測試doGet方法,分為beginDoGet(模擬測試參數設置)、DoGet(執行測試)、endDoGet(狀態結果驗證)
相比httpunit來說,寫測試更為容易,測試servlet更為專業,流程更為清晰,但是cactus需要容器支持,使得測試不可以自動進行,但是
如果使用一個嵌入式的容器,測試就可以自動了。
cactus是一個servlet和jsp的測試框架:http://jakarta.apache.org/cactus/getting_started.html
三 使用Jetty作為嵌入式容器測試servlet.
/**
* 一個關于嵌入式jetty測試的例子,jetty作為stubs的一個例子
*
*/
package com.easyjf.testexample;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.servlet.ServletHandler;
import com.meterware.httpunit.WebClient;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebResponse;
import junit.framework.Assert;
import junit.framework.TestCase;
public class JettySampleTest extends TestCase {
Server server;
protected void setUp() throws Exception {
//通過代碼設置并啟動一個服務器,該服務器是servlet的測試容器
super.setUp();
server = new Server();
Connector connector=new SocketConnector();
connector.setPort(80);
server.setConnectors(new Connector[]{connector});
ServletHandler handler=new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping("HelloWorld", "/");
server.start();
}
protected void tearDown() throws Exception {
super.tearDown();
server.stop();
}
public void testHellWorld() {
try {
WebConversation wc = new WebConversation();
WebResponse web = wc.getResponse("http://127.0.0.1/HelloWorld");
String result=web.getText();
Assert.assertEquals(result,"it works!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
可以發現,jetty可以充當一個servlet的容器,方便的是,jetty支持嵌入式服務,即可以通過代碼來啟動,
所以要寫自動測試的例子很方便,可以結合httpunit或者cactus進行servlet測試。
jetty主頁:http://docs.codehaus.org/display/JETTY/Embedding+Jetty
四 使用mock對象,此處使用easymock
import java.io.PrintWriter;
import java.io.Writer;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
public class MockTestServlet extends TestCase {
public void testService() throws Exception {
System.out.println("service");
HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletResponse response = createMock(HttpServletResponse.class);
//Creating the ServletConfig mock here
ServletConfig servletConfig = createMock(ServletConfig.class);
//Creating the ServletContext mock here
ServletContext servletContext = createMock(ServletContext.class);
//Create the target object
HelloWorld4 instance = new HelloWorld();
//初始化servlet,一般由容器承擔,一般調用servletConfig作為參數初始化,此處模擬容器行為
instance.init(servletConfig);
//在某些方法被調用時設置期望的返回值,如下這樣就不會去實際調用servletConfig的getServletContext方法,而是直接返回
//servletContext,由于servletConfig是mock出來的,所以可以完全控制。
expect(servletConfig.getServletContext()).andReturn(servletContext).anyTimes();
expect(request.getParameter("username")).andReturn("testuser");
PrintWriter pw=new PrintWriter(System.out,true);
expect(response.getWriter()).andReturn(pw).anyTimes();
//以上均是錄制,下面為重放,該種機制為easymock測試機制,要理解請看easymock測試的一些資料
replay(request);
replay(response);
replay(servletConfig);
replay(servletContext);
instance.doGet(request, response);
pw.flush();
//驗證結果是否預期,如果預期,則會在pw上寫出testuser.
verify(request);
verify(response);
verify(servletConfig);
verify(servletContext);
}
}
mock測試注重行為,mock對象其實都是模擬的對象,方法一般直接給出一個返回值,沒有具體的對象邏輯,mock對象
是用來幫助測試要測試的類的。比如要測試servlet的內部行為,又不想要容器等環境,就可以采用mock測試。
easymock是mock測試的一個框架:http://www.easymock.org/
發表于 @ 2007年02月10日 22:13:00|評論(2)
新一篇: 設計模式之創建模式 | 舊一篇: 服務定位器模式(service locator)wldandanpig 發表于2007年5月24日 10:09:40 IP:舉報
請問樓主
public String saveInfo()
{
String reqInfo = request.getParameter("reqInfo");
String sessInfo = (String)request.getSession().getAttribute("sessInfo");
request.setAttribute("reqInfo" , "response:"+reqInfo);
request.getSession().setAttribute("sessInfo", "response:"+reqInfo);
return "SUCCESS";
}
這個方法怎么測試啊cz_hyf 發表于2007年5月24日 17:20:23 IP:舉報
如果用httpunit的話
public void testHelloWorld() {
try {
// 創建Servlet的運行環境
ServletRunner sr = new ServletRunner();
// 向環境中注冊Servlet
sr.registerServlet("HelloWorld", HelloWorld.class.getName());
// 創建訪問Servlet的客戶端
ServletUnitClient sc = sr.newClient();
// 發送請求
WebRequest request = new GetMethodWebRequest("http://localhost/HelloWorld");
request.setParameter("reqInfo", "......");
InvocationContext ic = sc.newInvocation(request);
HelloWorld is = (HelloWorld) ic.getServlet();
// 測試servlet的某個方法
Assert.assertEquals(is.saveInfo,"SUCCESS");
} catch (Exception e) {
e.printStackTrace();
}
}
如果還不放心,不妨把request和request.session中的值取出來看看是否是你放進去的
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/cz_hyf/archive/2007/02/10/1507211.aspx