您的位置:首页 > 其它

给servlet写单元测试的总结

2007-02-10 22:13 639 查看
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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: