`
lxy19791111
  • 浏览: 481028 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

给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脚本,让测试进行。
 
 
使用该种方法测试的弱点就是:如果要使用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测试。
 

四 使用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/
 
分享到:
评论
2 楼 huajuande 2010-11-16  
太帅了~~~
1 楼 unsid 2009-03-09  
servlet挺难测试的,因为多数时候是返回一个页面代码,你很难写一个断言去对比response是否是你想要的.
我觉得mock会好一些,但还是不能解决太多问题,比如一个循环比预期少循环了一次导致的数据错误,如果循环中有代理对象,可以用代理对象被调用次数判断,如果仅仅是对输入参数进行某种加工才传到下层,加工过程中出错无法发现.

相关推荐

    单元测试的总结

    单元测试是软件开发过程中的重要环节,它允许开发者对代码的各个部分进行独立验证,确保它们按照预期工作。在Web开发中,传统的测试方法通常涉及启动整个Web服务器,执行测试,发现错误,然后停止服务器,修改代码,...

    servlet写的,登陆,注册,注销。

    在实际开发中,我们通常会编写单元测试或集成测试,以确保Servlet的各个功能正确无误。 总结起来,这个项目提供了一个基于Java Servlet的简单Web应用示例,展示了如何实现登录、注册和注销的核心功能。虽然它不涉及...

    easymock测试servlet

    Easymock是一个流行的Java库,它提供了创建和管理模拟对象的能力,帮助测试人员编写单元测试。 在"easymock测试servlet"的场景中,我们看到`SampleServletTest`类正在使用Easymock来测试`SampleServlet`类的行为。...

    spring单元测试

    总结起来,通过Java配置的Spring Web项目,我们可以利用JUnit、Mockito以及H2数据库轻松地进行单元测试。对于Controller层,我们使用`@WebMvcTest`注解;对于Service层,我们结合`@MockBean`和`@Autowired`创建mock...

    27. Spring Boot Junit单元测试【从零开始学Spring Boot】

    总结起来,Spring Boot与JUnit的结合使得单元测试变得简单而强大。通过编写清晰、全面的测试用例,我们可以有效地保证代码质量,减少线上故障,同时提高开发效率。在学习Spring Boot的过程中,掌握单元测试是非常...

    原生Servlet与Spring Controller性能比较--Servlet项目

    4. **扩展性和可维护性**:Spring MVC提供了更好的模块化和解耦,使得添加新功能、调整逻辑、单元测试更加方便,而原生Servlet的代码更容易变得复杂和难以维护。 在"AbTest"项目中,可以对两种方法进行基准测试,...

    servlet反射注解例子

    这对于创建通用的代码、框架或者进行单元测试非常有用。 接着,我们来看看注解。注解是Java提供的一种元数据,它可以为编译器、JVM或者工具提供有关代码的额外信息。注解不会改变代码的行为,但可以被编译器或工具...

    基于JSP和Servlet的简单自动贩卖机购物(软件测试作业)

    对于这个项目,可能的测试包括单元测试(对每个Servlet或JSP组件进行独立测试)、集成测试(检查不同组件之间的交互)和系统测试(整体功能测试)。此外,性能测试(如并发用户量测试)和安全测试(如SQL注入、XSS...

    单元测试junit

    ### 单元测试junit:理解与实践 在软件开发领域,单元测试是确保代码质量、功能正确性和可维护性的关键环节。JUnit作为Java领域最流行的单元测试框架之一,为开发者提供了一套全面且易用的工具,帮助他们编写高质量...

    一个servlet的web应用

    例如,使用HTTPS协议保护用户数据安全,使用连接池优化数据库访问,使用MVC(Model-View-Controller)设计模式分离业务逻辑和视图呈现,以及进行单元测试和集成测试确保软件质量。 总结来说,这个“一个servlet的...

    持续集成环境下运行单元测试和代码校验详细过程

    本篇文章将详细介绍在持续集成环境中运行单元测试和代码校验的详细过程。 首先,我们需要搭建持续集成环境。这个环境通常包括以下几个关键组件: 1. **JDK**:Java Development Kit 是开发和运行 Java 应用的基础...

    MVC架构 Servlet

    - **易于测试**:由于职责明确,每个组件都可以单独进行单元测试。 - **可重用性**:模型和控制器可以复用,视图可以根据需求进行定制。 - **更好的组织结构**:MVC架构有助于创建模块化、层次化的代码结构。 ...

    java 测试

    【标题】"Java 测试" 涵盖了Java编程语言中的测试技术,这包括单元测试、集成测试、系统测试等多个层次。Java测试是确保代码质量、提高软件可靠性的重要环节,它通过自动化的方式验证程序的功能是否按预期工作,以及...

    网上书店(jsp+servlet)

    总结来说,"网上书店(jsp+servlet)"项目是一个完整的Java Web应用程序,涵盖了前端展示、后端服务、数据库交互等多个方面,对于学习和实践JSP和Servlet技术是一个很好的案例。项目文档和依赖包提供了深入理解系统...

    JAVA+JSP+Servlet+android+SSH视频教程全集+项目视频 亲自总结

    4. **测试与调试**:单元测试、集成测试、性能测试。 5. **部署上线**:服务器选择、环境搭建、部署流程。 通过以上知识点的学习,相信学员们能够全面地掌握JAVA+JSP+Servlet+Android+SSH等相关技术,并能够在实际...

    使用JSP/Servlet/Ajax技术开发新闻发布系统

    为了确保代码的质量,开发者可能会使用JUnit等工具对Servlet和JSP中的业务逻辑进行单元测试,确保每个功能模块的正确性。 【部署与发布】 完成开发后,新闻发布系统会被打包成WAR文件,然后部署到Web服务器上,如将...

    mock struts1 测试

    在软件开发过程中,单元测试是一种重要的质量保证手段。对于基于Struts框架的应用程序来说,如何有效地进行单元测试尤为重要。Struts1作为早期广泛使用的MVC框架之一,在很多遗留系统中仍然占有一席之地。而Mock ...

    基于JSP_Servlet_JavaBean的电子书店

    10. **测试与部署**:项目完成后,需要进行单元测试、集成测试和系统测试,确保所有功能正常工作。最后,将项目打包成WAR文件,部署到服务器(如Tomcat或Jetty)上,供用户访问。 总结起来,这个“基于JSP_Servlet_...

Global site tag (gtag.js) - Google Analytics