`
lylyb
  • 浏览: 88985 次
  • 性别: Icon_minigender_1
  • 来自: 烟台
社区版块
存档分类
最新评论

给servlet写单元测试的总结(转)

    博客分类:
  • JAVA
阅读更多
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/
分享到:
评论

相关推荐

    struts2的总结,适合初学者

    这两个参数与容器相关,如果想在servlet中作单元测试,则必须初始化这两个参数。 4、如果一个servlet中有很多个方法,则必须采用传递参数的形式,分解到每一个方法中。 2重构servlet 针对servlet以上的特点,我们...

    software-testing-interview-question:这是一个关于软件测试面试题目的列表,收集了关于测试理论,自动化测试,性能测试以及其他一些软件测试相关的面试题目

    解释下单元测试,集成测试,系统测试以及验收测试?探索性测试是什么?应该怎么做?什么是冒烟测试,如何有效的开展冒烟测试?一条高质量的缺陷记录(Bug)应该具有哪些内容?缺陷的生命周期是怎样的?Alpha测试与Beta测试...

    Spring.3.x企业应用开发实战(完整版).part2

    16.7.1 对LoginController进行单元测试 16.7.2 使用Spring Servlet API模拟对象 16.7.3 使用Spring RestTemplate测试 16.7.4 使用Selenium测试 16.8 小结 第17章 实战案例开发 17.1 论坛案例概述 17.1.1 论坛整体...

    Spring3.x企业应用开发实战(完整版) part1

    16.7.1 对LoginController进行单元测试 16.7.2 使用Spring Servlet API模拟对象 16.7.3 使用Spring RestTemplate测试 16.7.4 使用Selenium测试 16.8 小结 第17章 实战案例开发 17.1 论坛案例概述 17.1.1 论坛整体...

    struts2+spring2+ibates

    2、在sping配置中注意单元测试里,xml文件的路径问题,要用绝对路径。 3、struts.xml中命名空间和拦截器的使用。 4、sqlmapconfig.xml中传入参数和result的设置,只需要将得到的值result映射到有此属性的类对象. 5、...

    JAVA项目开发全程实录(含电子书和所有源代码)

    1.7.5 单元测试 32 1.8 进货管理模块设计 36 1.8.1 进货管理模块概述 36 1.8.2 进货管理模块技术分析 38 1.8.3 进货单实现过程 38 1.9 查询统计模块设计 42 1.9.1 查询统计模块概述 42 1.9.2 查询统计模块技术分析 ...

    java三大框架

    使用Spring构建的应用程序易于单元测试。 Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。 Spring帮助你解决许多问题而无需...

    java面试题以及技巧

    │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java.htm │ │ │ SCJP 1_4 认证的初级教程.htm │ │ │ 新建 文本文档....

    java面试题目与技巧1

    │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java.htm │ │ │ SCJP 1_4 认证的初级教程.htm │ │ │ 新建 文本文档....

    java面试题及技巧4

    │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java.htm │ │ │ SCJP 1_4 认证的初级教程.htm │ │ │ 新建 文本文档....

    java面试题及技巧3

    │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java.htm │ │ │ SCJP 1_4 认证的初级教程.htm │ │ │ 新建 文本文档....

    java面试题以及技巧6

    │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java.htm │ │ │ SCJP 1_4 认证的初级教程.htm │ │ │ 新建 文本文档....

    Maven权威指南 很精典的学习教程,比ANT更好用

    添加单元测试资源 4.12. 执行单元测试 4.12.1. 忽略测试失败 4.12.2. 跳过单元测试 4.13. 构建一个打包好的命令行应用程序 5. 一个简单的Web应用 5.1. 介绍 5.1.1. 下载本章样例 5.2. 定义这个简单的...

    Spring中文帮助文档

    8.2.2. 单元测试支持类 8.3. 集成测试 8.3.1. 概览 8.3.2. 使用哪个支持框架 8.3.3. 通用目标 8.3.4. JDBC测试支持 8.3.5. 常用注解 8.3.6. JUnit 3.8遗留支持 8.3.7. Spring TestContext Framework 8.3.8....

    Spring API

    8.2.2. 单元测试支持类 8.3. 集成测试 8.3.1. 概览 8.3.2. 使用哪个支持框架 8.3.3. 通用目标 8.3.4. JDBC测试支持 8.3.5. 常用注解 8.3.6. JUnit 3.8遗留支持 8.3.7. Spring TestContext Framework 8.3.8....

    Hibernate中文详细学习文档

    1.4.1. 编写基本的servlet 1.4.2. 处理与渲染 1.4.3. 部署与测试 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. JMX整合 2.4. 对JCA的支持 2.5. 上下文相关的(Contextual...

    Hibernate+中文文档

    1.4.1. 编写基本的servlet 1.4.2. 处理与渲染 1.4.3. 部署与测试 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. JMX整合 2.4. 对JCA的支持 2.5. 上下文相关的(Contextual...

    Hibernate参考文档

    1.4.1. 编写基本的servlet 1.4.2. 处理与渲染 1.4.3. 部署与测试 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. JMX整合 2.4. 对JCA的支持 2.5. 上下文相关的(Contextual)Session...

    hibernate 体系结构与配置 参考文档(html)

    编写基本的servlet 1.4.2. 处理与渲染 1.4.3. 部署与测试 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. JMX整合 2.4. 对JCA的支持 2.5. 上下文相关的(Contextual)...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    1.4.1. 编写基本的servlet 1.4.2. 处理与渲染 1.4.3. 部署与测试 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. JMX整合 2.4. 对JCA的支持 2.5. 上下文相关的(Contextual...

Global site tag (gtag.js) - Google Analytics