聊聊单元測试(一)——EasyMock
一、单元測试是保证软件质量的重要方法。
单元測试是对系统中某个模块功能的验证,但我们总会遇到这样那样的问题,导致測试代码非常难编写。最直接的一个原因便是强耦合关系,被測试者依赖一些不easy构造,比較复杂的对象,如:假设要測试一个servlet,我们必须获得HttpServletRequest,甚至须要一个Web容器;假设要測试Dao层,我们可能要获得JDBC相关对象,终于获得ResultSet。这些对象的构建并不那么easy,假设我们使用Mock方法(常见的一种单元測试技术,它的主要作用是模拟一些在应用中不easy构造或者比較复杂的对象,从而把測试与測试边界以外的对象隔离开),编写自己定义Mock对象是能够解决这个问题,但引入额外复杂代码的同一时候,非常easy引入额外的错误。
二、发现的源动力就是不将就!
面对上述问题,有非常多开源项目对动态构建 Mock 对象提供了支持,这些项目可以依据现有的接口或类动态生成Mock对象,这样不仅能避免额外的编码工作,同一时候也减少了引入错误的可能。
EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock 对象的类库。它提供对接口的模拟,能够通过录制、回放、检查三步来完毕大体的測试过程,能够验证方法的调用种类、次数、顺序,能够令 Mock 对象返回指定的值或抛出指定异常。通过 EasyMock,我们能够方便的构造 Mock 对象从而使单元測试顺利进行。
三、使用EasyMock完毕单元測试的过程大致能够划分为下面几个步骤:
- 1、使用 EasyMock 生成 Mock 对象;
- 2、设定 Mock 对象的预期行为和输出;
- 3、将 Mock 对象切换到 Replay 状态;
- 4、调用 Mock 对象方法进行单元測试;
- 5、对 Mock 对象的行为进行验证。
四、文字表达有时候是苍白的,想不通过代码说事,还不行,看样子离大师还是有一段距离的。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*; public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// check username & password:
if("admin".equals(username) && "123456".equals(password)) {
ServletContext context = getServletContext();
RequestDispatcher dispatcher = context.getNamedDispatcher("dispatcher");
dispatcher.forward(request, response);
}
else {
throw new RuntimeException("Login failed.");
}
} }
这个Servlet实现简单的用户验证的功能,若username和口令匹配“admin”和“123456”,则请求被转发到指定的dispatcher上,否则,直接抛出RuntimeException。
为了測试doPost()方法,我们须要模拟HttpServletRequest,ServletContext和RequestDispatcher对象,以便脱离J2EE容器来測试这个Servlet。
完整的LoginServletTest代码例如以下:
import javax.servlet.*;
import javax.servlet.http.*;
import org.easymock.*; public class LoginServletTest {
// 測试登陆失败
@Test
public void testLoginFailed() throws Exception {
// 使用 EasyMock 生成 Mock 对象;
MockControl mc = MockControl.createControl(HttpServletRequest.class);
HttpServletRequest request = (HttpServletRequest)mc.getMock();
// 设定 Mock 对象的预期行为和输出;
request.getParameter("username");
mc.setReturnValue("admin", 1);
request.getParameter("password");
mc.setReturnValue("1234", 1);
// 将 Mock 对象切换到 Replay 状态;
mc.replay();
// now start test:
LoginServlet servlet = new LoginServlet();
try {
// 里面会调用 Mock 对象方法进行单元測试;
servlet.doPost(request, null);
fail("Not caught exception!");
}
catch(RuntimeException re) {
assertEquals("Login failed.", re.getMessage());
}
// 对 Mock 对象的行为进行验证。
mc.verify();
}
// 測试登陆成功
@Test
public void testLoginOK() throws Exception {
// 使用 EasyMock 生成 Mock 对象;
MockControl requestCtrl = MockControl.createControl(HttpServletRequest.class);
HttpServletRequest requestObj = (HttpServletRequest)requestCtrl.getMock();
MockControl contextCtrl = MockControl.createControl(ServletContext.class);
final ServletContext contextObj = (ServletContext)contextCtrl.getMock();
MockControl dispatcherCtrl = MockControl.createControl(RequestDispatcher.class);
RequestDispatcher dispatcherObj = (RequestDispatcher)dispatcherCtrl.getMock();
// 设定 Mock 对象的预期行为和输出;
requestObj.getParameter("username");
requestCtrl.setReturnValue("admin", 1);
requestObj.getParameter("password");
requestCtrl.setReturnValue("123456", 1);
contextObj.getNamedDispatcher("dispatcher");
contextCtrl.setReturnValue(dispatcherObj, 1);
dispatcherObj.forward(requestObj, null);
dispatcherCtrl.setVoidCallable(1);
// 将 Mock 对象切换到 Replay 状态;
requestCtrl.replay();
contextCtrl.replay();
dispatcherCtrl.replay();
// 里面会调用 Mock 对象方法进行单元測试;
//为了让getServletContext()方法返回我们创建的ServletContext Mock对象,我们定义一个匿名类并覆写getServletContext()方法:
LoginServlet servlet = new LoginServlet() {
public ServletContext getServletContext() {
return contextObj;
}
};
servlet.doPost(requestObj, null);
// 对 Mock 对象的行为进行验证。
requestCtrl.verify();
contextCtrl.verify();
dispatcherCtrl.verify();
}
}
五、总结
EasyMock 推荐依据指定接口动态构建 Mock 对象,这促使我们遵循“面向接口编程”的原则:假设不面向接口,则測试难于进行。是否easy进行单元測试也体现了代码质量的高低,难以測试的代码,通常也是充满坏味道的代码。能够这么说,假设代码在单元測试中难于应用,则它在真实环境中也将难于应用。总之,创建尽可能easy測试的代码就是创建高质量的代码。
聊聊单元測试(一)——EasyMock的更多相关文章
- 利用Continuous Testing实现Eclipse环境自己主动单元測试
当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...
- 在Eclipse中使用JUnit4进行单元測试(0基础篇)
本文绝大部分内容引自这篇文章: http://www.devx.com/Java/Article/31983/0/page/1 我们在编写大型程序的时候,须要写成千上万个方法或函数,这些函数的功能可能 ...
- C语言单元測试
C语言单元測试 对于敏捷开发来说,单元測试不可缺少,对于Java开发来说,JUnit非常好,对于C++开发,也有CPPUnit可供使用,而对于传统的C语言开发,就没有非常好的工具可供使用,能够找到的有 ...
- OpenStack中给wsgi程序写单元測试的方法
在 OpenStack 中, 针对web应用, 有三种方法来写单元測试 1) 使用webob生成模拟的request from __future__ import print_function imp ...
- Android单元測试之JUnit
随着近期几年測试方面的工作慢慢火热起来.常常看见有招聘測试project师的招聘信息.在Java中有单元測试这么一个JUnit 方式,Android眼下主要编写的语言是Java,所以在Android开 ...
- 让你提前认识软件开发(19):C语言中的协议及单元測试演示样例
第1部分 又一次认识C语言 C语言中的协议及单元測试演示样例 [文章摘要] 在实际的软件开发项目中.常常要实现多个模块之间的通信.这就须要大家约定好相互之间的通信协议,各自依照协议来收发和解析消息. ...
- php单元測试
你是否在程序开发的过程中遇到下面的情况:当你花了非常长的时间开发一个应用后,你觉得应该是大功告成了,可惜在调试的时候,老是不断的发现bug,并且最可怕的是,这些bug是反复出现的,你可能发现这些bug ...
- Android 进行单元測试难在哪-part3
原文链接 : HOW TO MAKE OUR ANDROID APPS UNIT TESTABLE (PT. 1) 原文作者 : Matthew Dupree 译文出自 : 开发技术前线 www.de ...
- iOS 单元測试之XCTest具体解释(一)
原创blog,转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的iOS-SDK具体解释专栏 http://blog.csdn.net/column/details/huang ...
随机推荐
- 查看oracle数据库的连接数以及用户
查看oracle数据库的连接数以及用户 11.查询oracle的连接数2select count(*) from v$session;32.查询oracle的并发连接数4select count(*) ...
- Apache Commons Math3学习笔记(2) - 多项式曲线拟合(转)
多项式曲线拟合:org.apache.commons.math3.fitting.PolynomialCurveFitter类. 用法示例代码: // ... 创建并初始化输入数据: double[] ...
- HDU 1864最大报销额(一维背包)
题目地址:HDU 1864 刚上来看着挺麻烦的..细致看了看原来好简单好简单...仅仅要去掉一些不符合要求的发票,剩下的就是最简单的背包问题了..对于小数问题,仅仅要*100就变成整数了. 代码例如以 ...
- 关于Windows azure从github上部署项目
自己做了一个闪存解析的webapi,今天尝试了一下加一个HelpPage,本地访问正常,但是在azure上就报错. 项目是不熟在WindowsAzure上的,项目自动同步github上的项目.gith ...
- 【甘道夫】HBase连接池 -- HTablePool是Deprecated之后
说明: 近期两天在调研HBase的连接池,有了一些收获,特此记录下来. 本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然后查 ...
- 严格模式 (JavaScript)
严格模式是一种将更好的错误检查引入代码中的方法. 在使用严格模式时,您无法使用隐式声明的变量.将值赋给只读属性或将属性添加到不可扩展的对象. 〉声明严格模式 可以通过在文件.程序或函数的开头添加 &q ...
- JS封深入了解
1. javascript 语言理解闭包 js变量的范围分成两个:全局变量.局部变量.在全局变量的函数外声明变量,内部功能可以直接调用全局变量.声明变量里面的函数必须使用var 命令,否则,它里面的函 ...
- Windows下Jekyll安装
一直用Mac,换了新公司使用的电脑是windows,网上粗略的看了一下Jekyll的安装.简略的实现了一遍 首先安装Ruby Ruby安装文件下载地址 下载对应版本,我的电脑是64位的下载64位的版本 ...
- Spring面试问答Top 25
欢迎大家向我推荐你在面试过程中遇到关于Spring的问题. 我会把大家推荐的问题加入到以下的Spring经常使用面试题清单中供大家參考. 问题清单: 什么是Spring框架?Spring框架有哪些主要 ...
- 解决 Mybatis 元素类型为 "resultMap" 的内容必须匹配 "(constructor?,id*,result*,association*,collection*,discriminat
在配置 mybatis mapper.xml文件时, 一不小心就会报如下类似的异常: Caused by: org.springframework.beans.factory.BeanCreation ...