`
yangjizhong24
  • 浏览: 395758 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tdd:测试驱动WEB组件

阅读更多

相信大家有好多人会使用JUNIT进行单元测试了,但是在WEB开发中仅仅对MVC设计模式中业务逻辑进行测试还是远远不够的,如何对 控制器视图层进行单元测试将是本文的重点:

 

主要分享的内容:

 

一.测试驱动 Java  Servlet

二.测试驱动 Spring 控制器

三.用JspTest 测试驱动JSP

 

开始吧。

 

一.测试驱动 Java  Servlet

servlet通常会有一两个公有方法,每个公有方法处理一种类型的HTTP请求,例如:GET,POST,HEAD,PUT等。每个方法都以doXXX格式命名。大部分情况下都只处理GET和POST请求而已。基类javax.servlet.http.HttpServlet的service方法负责处理所有HTTP请求,其会根据HTTP请求类型把请求转发到对应的doXXX方法上。

 

doXXX方法的第一个参数HttpServletRequest封装了HTTP请求,其包含请求相关参数,HTTP头及其他信息。

第二个参数HttpServletResponse主要用于给客户端回送应答。任何发给浏览器的HTTP头都可以放到应答对象中。所有想输出的内容都可以转给应答中的printWriter对象和ServletOutputStream对象。

 

实例:

1.模拟请求和应答

 

	package com.tddinaction.j2ee.web.controller.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class EchoServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        PrintWriter writer = response.getWriter();
        for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
            String parameter = String.valueOf(e.nextElement());
            String[] values = request.getParameterValues(parameter);
            for (int i = 0; i < values.length; i++) {
                writer.write(parameter + "=" + values[i]);
                writer.write("\n");
            }
        }
        writer.close();
    }
}


package com.tddinaction.j2ee.web.controller.servlet;

import junit.framework.TestCase;

import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

public class EchoServletTest extends TestCase {

	@Test
	public void testEchoingParametersWithMultipleValues() throws Exception {
		//通过第三方的测试替身来模拟请求对象和应答对象。用来模拟浏览器发起的请求
		MockHttpServletRequest request = new MockHttpServletRequest();
		MockHttpServletResponse response = new MockHttpServletResponse();

		request.addParameter("param1", "param1value1");
		request.addParameter("param2", "param2value1");
		request.addParameter("param2", "param2value2");
		new EchoServlet().doGet(request, response);
		String[] lines = response.getContentAsString().split("\n");
		assertEquals("Expected as many lines as we have parameter values", 3, lines.length);
		assertEquals("param1=param1value1", lines[0]);
		assertEquals("param2=param2value1", lines[1]);
		assertEquals("param2=param2value2", lines[2]);
	}
}

 

 2.测试重定向

 

package com.tddinaction.j2ee.web.controller.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String user = request.getParameter("j_username");
		String pass = request.getParameter("j_password");
		if (isValidLogin(user, pass)) {
			request.getSession().setAttribute("username", user);
			response.sendRedirect("/frontpage");
		} else {
			forwardTo("/invalidlogin", request, response);
		}
	}

	private boolean isValidLogin(String user, String pass) {
		if (pass.equals("correctpassword")) {
			return true;
		} else if (pass.equals("wrongpassword")) {
			return false;
		}
		return false;
	}

	private void forwardTo(String path, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		RequestDispatcher dispatcher = request.getRequestDispatcher(path);
		dispatcher.forward(request, response);
	}
}


package com.tddinaction.j2ee.web.controller.servlet;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

public class TestLoginServlet {

	private static final String VALID_USERNAME = "validuser";

	private LoginServlet servlet;

	private MockHttpServletRequest request;

	private MockHttpServletResponse response;

	@Before
	public void setUp() {
		servlet = new LoginServlet();
		request = new MockHttpServletRequest();
		response = new MockHttpServletResponse();
	}

	@Test
	public void wrongPasswordShouldRedirectToErrorPage() throws Exception {
		request.addParameter("j_username", VALID_USERNAME);
		request.addParameter("j_password", "wrongpassword");
		servlet.service(request, response);
		assertUserEndedUpOnPage("/invalidlogin");
	}

	@Test
	public void validLoginForwardsToFrontPageAndStoresUsername() throws Exception {
		request.addParameter("j_username", VALID_USERNAME);
		request.addParameter("j_password", "correctpassword");
		servlet.service(request, response);
		assertUserEndedUpOnPage("/frontpage");
		assertEquals(VALID_USERNAME, request.getSession().getAttribute("username"));
	}

	private void assertUserEndedUpOnPage(String expected) {
		String actual = response.getRedirectedUrl();
		if (actual == null) {
			actual = response.getForwardedUrl();
		}
		assertEquals(expected, actual);
	}
}

 

 

二.测试驱动 Spring 控制器

 

 1.失败的登录:

 

package com.tddinaction.j2ee.web.controller.spring;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.tddinaction.j2ee.web.controller.authenticator.Authenticator;

public class LoginController implements Controller {

    private Authenticator authenticator;

    public void setAuthenticator(Authenticator authenticator) {
        this.authenticator = authenticator;
    }

    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        String user = request.getParameter("j_username");
        String pass = request.getParameter("j_password");
        if (authenticator.isValidLogin(user, pass)) {
            return new ModelAndView("frontpage");
        }
        return new ModelAndView("wrongpassword");
    }
}


package com.tddinaction.j2ee.web.controller.spring;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.ModelAndView;

import com.tddinaction.j2ee.web.controller.authenticator.MockAuthenticator;

public class TestLoginController {

	private static final String CORRECT_PASSWORD = "correctpassword";

	private static final String VALID_USERNAME = "validuser";

	private MockHttpServletRequest request;

	private MockHttpServletResponse response;

	private LoginController controller;

	@Before
	public void setUp() {
		request = new MockHttpServletRequest();
		response = new MockHttpServletResponse();
		controller = new LoginController();

		MockAuthenticator auth = new MockAuthenticator();
		auth.addUser(VALID_USERNAME, CORRECT_PASSWORD);
		controller.setAuthenticator(auth);
	}

	@Test
	public void wrongPasswordShouldRedirectToErrorPage() throws Exception {
		request.addParameter("j_username", "noSuchUsername");
		request.addParameter("j_password", "noSuchPassword");
		ModelAndView v = controller.handleRequest(request, response);

		assertEquals("wrongpassword", v.getViewName());
	}

	@Test
	public void validLoginForwardsToFrontPageAndStoresUsername() throws Exception {
		request.addParameter("j_username", VALID_USERNAME);
		request.addParameter("j_password", CORRECT_PASSWORD);
		ModelAndView v = controller.handleRequest(request, response);

		assertEquals("frontpage", v.getViewName());
	}
}

 

 

三.用JspTest 测试驱动JSP

 

JSPTEST是个开源库,他会把JSP编译成SERVLET类然后再执行此SERVLET。详细请登录其官网:

http://sourceforge.net/projects/jsptest/

 

jsptest里有一个叫做HtmlTestCase的抽象类,所有测试都需要继承这个类。HtmlTestCase提供了一些方法来模拟HTTP请求和渲染JSP文件以及做HTTP相关的验证等

JspTest默认在工程目录下开始寻找JSP文件。

 

测试FORM表单元素:

package com.tddinaction.j2ee.web.view.jsp.jsptest;

import net.sf.jsptest.HtmlTestCase;

public class LoginPageTest extends HtmlTestCase {

	@Override
	protected String getWebRoot() {
		return "src/test/resources/websrc/jsp";
	}

	public void testFormFieldsArePresent() throws Exception {
		get("/login.jsp");
		form().shouldHaveField("j_username");
		form().shouldHaveField("j_password");
		form().shouldHaveField("ddd");
		form().shouldHaveSubmitButton("login");

	}

	public void testPreviousUsernameIsRetained() throws Exception {
		setRequestAttribute("j_username", "bob");
		get("/login.jsp");
		form().field("j_username").shouldHaveValue("bob");
	}
}
//login.jsp

<%@ page language="Java" %>
<html>
  <body>
    <form>
    	<%
    	  String username = (String) request.getAttribute("j_username");
    	  if (username == null) username = "";
    	%>
      <input type="text" name="j_username" value="<%= username %>"/>
      <input type="password" name="j_password" />
      <input type="submit" name="ddd" value="login" />
    </form>
  </body>
</html>

 

 

 

 

分享到:
评论
1 楼 jellyx 2012-07-11  
JSPTEST 一开始是报没各种JAR包,然后从tomcate复制进来,最后又报很多错。总之恶性循环的。怎么办呢

相关推荐

    测试驱动开发的艺术

    TDD入门第3章 小步重构第4章 TDD的概念与模式第二部分 针对特定技术应用TDD第5章 测试驱动Web组件第6章 测试驱动数据访问第7章 测试驱动不可预测功能第8章 测试驱动Swing代码第三部分 基于ATDD构建产品第9章 解析...

    测试驱动器:用于编写Web组件测试的有思想的库

    Test Drive是一个自以为是,但与框架无关的工具,匹配器和帮助器的集合,用于高效地进行Web应用程序,GUI和客户端组件的“测试驱动开发”。 基于现有的开源项目以及原始的贡献和想法,它不仅提供实用且有效的解决...

    spring-rest-no-xml:简单的核心项目,显示无 xml spring 配置并将 Ports&Adapters 架构与 DDD 相结合

    DDD 组件:EventPublisher、Saga、Functional Closure 休息建筑 Angrular js 前端 Spring无xml配置 Spring启动应用程序 单元测试完全覆盖的 TDD 项目 参考资料 VAUGHN VERNON:实现领域驱动设计 SLAWOMIR SOBOTKA/...

    mojave:一个基于注释的基于POJO的Java Web MVC框架,支持Guice的DI

    它试图: 通过提供IoC功能,促进TDD和依赖注入,并最终开发去耦组件通过提供单线程编程模型消除Web应用程序开发中的并发问题通过拦截器模式支持AOP,从Web应用程序开发中消除横切关注点尽可能少地侵入框架;...

    《非程序员》第51期

    虽然TDD所编写的测试用例在一定程度上为寻找bug提供了依据,但事实上,按照TDD的方式进行的软件开发是不可能通过TDD再找到bug的(想想我们前面说的“完工时完工”),你想啊,当我们的代码完成的时候,所有的测试...

    infinite-java-code:额外课程作业

    测试驱动开发 (TDD)。 使用文件和文件系统。 数据流。 分布式应用程序(java.net 包)。 UDP 和 TCP 协议的使用。 HTTP 协议。 Web 应用程序的设计。 Java Servlet 和 Java 服务器页面 (JSP)。 网页表格。 阿帕奇...

    matlab代码替换-CV:蒂姆·霍金斯(TimHawkins)-简历

    在测试驱动和领域驱动设计方面积累了经验 使用Splunk创建仪表板以监控站点性能并在最终用户受到影响之前捕获问题 改造了结帐前端组件以使用React和Atomic设计 Web App开发人员-Vegitable Ltd:个人项目 开发了素食...

    富裕性:一个简单,安全且可扩展PHP应用程序框架

    得益于测试驱动开发(TDD),该框架可靠且经过了全面测试。 富丽堂皇分为多个组件,可以分别安装或捆绑在一起。安装可以使用Composer安装Opulence: composer create-project opulence/project --prefer-dist文献...

    一个简单,安全且可扩展PHP应用程序框架-PHP开发

    Opulence简介Opulence是一个PHP Web应用程序框架,它简化了创建和维护安全,可扩展网站的困难部分。...得益于测试驱动开发(TDD),该框架可靠且经过了全面测试。 富丽堂皇分为多个组件,可以单独安装

    reddi-dotnet-react-app:带有React和其他一些有用插件的.NET Core 2.1应用,可用于快速迭代原型设计

    .NET Core 2.1 Web App(API /后端) React(前端) React路由器(路由) 情感(用于启用可测试的样式化组件,同时保持与CSS表示法接近) 故事书(视觉交互设计) 开玩笑(TDD和RDD(自述驱动开发)) 酶(视觉行为...

    [Android开发权威指南].李宁.扫描版.pdf

    第22章 测试驱动开发 TDD 第四部分 综合实例篇 第23章 Android综合案例一 蓝牙聊天 第24章 Android综合案例二 月球登陆 游戏 第25章 Android综合案例三 全键盘输入法 应用 第26章 Android综合案例四 贪吃蛇 游戏 ...

    D3.js数据可视化实战手册.epub

    第1章,D3入门指南,是D3.js预热。它涵盖了一些基本概念,诸如D3.js是什么,以及如何搭建一个适用于D3.js数据可视化程序的开发环境等。...第13章,测试驱动,帮助你使用TDD的方式来实现可视化程序。

    endangerous-outfitters

    使用TDD来驱动Rails开发的所有层,包括单元,集成和用户验收测试 设计一个使用一对一,一对多和多对多关系的模型系统 练习混合HTML,CSS和Rails模板以创建邀请和可用的用户界面 区分Rails堆栈中各个组件的职责 建立

    Visual.Basic.2010.&.NET4.高级编程(第6版)-文字版.pdf

    第7章 测试驱动的开发 287 7.1 测试的内容和方式 288 7.2 visual studio中的tdd工具 290 7.3 单元测试过程 291 7.3.1 创建测试程序 291 7.3.2 运行测试程序 294 7.3.3 测试数据访问代码 295 7.3.4 ...

Global site tag (gtag.js) - Google Analytics