`
piperzero
  • 浏览: 3471951 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

看了抛哥的mock留言,找了找easymock,留个笔记,分享给大家!

 
阅读更多

看了抛哥的mock留言,找了找easymock,留个笔记,分享给大家!

    博客分类:
  • J2SE

单元测试是XP 极力推荐的测试驱动开发模式,是保证软件质量的重要方法。尽管如此,对许多

类的单元测试仍然是极其困难的,例如,对数据库操作的类进行测试,如果不准备好数据库环境以

及相关测试数据,是很难进行单元测试的;再例如,对需要运行在容器内的Servlet 或EJB 组件,脱

离了容器也难于测试。

幸运的是,Mock Object 可以用来模拟一些我们需要的类,这些对象被称之为模仿对象,在单元

测试中它们特别有价值。

Mock Object 用于模仿真实对象的方法调用,从而使得测试不需要真正的依赖对象。Mock Object

只为某个特定的测试用例的场景提供刚好满足需要的最少功能。它们还可以模拟错误的条件,例如

抛出指定的异常等。

目前,有许多可用的Mock 类库可供我们选择。一些Mock 库提供了常见的模仿对象,例如:

HttpServletRequest,而另一些Mock 库则提供了动态生成模仿对象的功能,本文将讨论使用EasyMock

动态生成模仿对象以便应用于单元测试。

到目前为止,EasyMock 提供了1.2 版本和2.0 版本,2.0 版本仅支持Java SE 5.0,本例中,我们

选择EasyMock 1.2 for Java 1.3 版本进行测试,可以从http://www.easymock.org 下载合适的版本。

我们首先来看一个用户验证的LoginServlet 类:

Java代码 复制代码收藏代码
  1. /**
  2. *LoginServlet.java
  3. */
  4. packagecom.javaeedev.test.mock;
  5. importjava.io.*;
  6. importjavax.servlet.*;
  7. importjavax.servlet.http.*;
  8. publicclassLoginServletextendsHttpServlet{
  9. protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
  10. throwsServletException,IOException{
  11. Stringusername=request.getParameter("username");
  12. Stringpassword=request.getParameter("password");
  13. //checkusername&password:
  14. if("admin".equals(username)&&"123456".equals(password)){
  15. ServletContextcontext=getServletContext();
  16. RequestDispatcherdispatcher=context.getNamedDispatcher("dispatcher");
  17. dispatcher.forward(request,response);
  18. }else{
  19. thrownewRuntimeException("Loginfailed.");
  20. }
  21. }
  22. }

这个Servlet 实现简单的用户验证的功能,若用户名和口令匹配“admin”和“123456”,则请求

被转发到指定的dispatcher 上,否则,直接抛出RuntimeException。

为了测试doPost()方法,我们需要模拟HttpServletRequest,ServletContext 和RequestDispatcher

对象,以便脱离J2EE 容器来测试这个Servlet。

我们建立TestCase,名为LoginServletTest:

Java代码 复制代码收藏代码
  1. publicclassLoginServletTestextendsTestCase{
  2. }

我们首先测试当用户名和口令验证失败的情形, 演示如何使用EasyMock 来模拟

HttpServletRequest 对象:

Java代码 复制代码收藏代码
  1. publicvoidtestLoginFailed()throwsException{
  2. MockControlmc=MockControl.createControl(HttpServletRequest.class);
  3. HttpServletRequestrequest=(HttpServletRequest)mc.getMock();
  4. //setMockObjectbehavior:
  5. request.getParameter("username");
  6. mc.setReturnValue("admin",1);
  7. request.getParameter("password");
  8. mc.setReturnValue("1234",1);
  9. //ok,allbehaviorsareset!
  10. mc.replay();
  11. //nowstarttest:
  12. LoginServletservlet=newLoginServlet();
  13. try{
  14. servlet.doPost(request,null);
  15. fail("Notcaughtexception!");
  16. }catch(RuntimeExceptionre){
  17. assertEquals("Loginfailed.",re.getMessage());
  18. }
  19. //verify:
  20. mc.verify();
  21. }

仔细观察测试代码,使用EasyMock 来创建一个Mock 对象需要首先创建一个MockControl:

Java代码 复制代码收藏代码
  1. MockControlmc=MockControl.createControl(HttpServletRequest.class);

然后,即可获得MockControl 创建的Mock 对象:

Java代码 复制代码收藏代码
  1. HttpServletRequestrequest=(HttpServletRequest)mc.getMock();

下一步,我们需要“录制”Mock 对象的预期行为。在LoginServlet 中, 先后调用了

request.getParameter("username") 和request.getParameter("password") 两个方法, 因此, 需要在

MockControl 中设置这两次调用后的指定返回值。我们期望返回的值为“admin”和“1234”:

Java代码 复制代码收藏代码
  1. request.getParameter("username");//期望下面的测试将调用此方法,参数为"username"
  2. mc.setReturnValue("admin",1);//期望返回值为"admin",仅调用1次
  3. request.getParameter("password");//期望下面的测试将调用此方法,参数为"password"
  4. mc.setReturnValue("1234",1);//期望返回值为"1234",仅调用1次

紧接着,调用mc.replay(),表示Mock 对象“录制”完毕,可以开始按照我们设定的方式运行,

我们对LoginServlet 进行测试,并预期会产生一个RuntimeException:

Java代码 复制代码收藏代码
  1. LoginServletservlet=newLoginServlet();
  2. try{
  3. servlet.doPost(request,null);
  4. fail("Notcaughtexception!");
  5. }catch(RuntimeExceptionre){
  6. assertEquals("Loginfailed.",re.getMessage());
  7. }

由于本次测试的目的是检查当用户名和口令验证失败后, LoginServlet 是否会抛出

RuntimeException,因此,response 对象对测试没有影响,我们不需要模拟它,仅仅传入null 即可。

最后,调用mc.verify()检查Mock 对象是否按照预期的方法调用正常运行了。

运行JUnit,测试通过!表示我们的Mock 对象正确工作了!

下一步,我们来测试当用户名和口令匹配时,LoginServlet 应当把请求转发给指定的

RequestDispatcher。在这个测试用例中,我们除了需要HttpServletRequest Mock 对象外,还需要模拟

ServletContext 和RequestDispatcher 对象:

Java代码 复制代码收藏代码
  1. MockControlrequestCtrl=MockControl.createControl(HttpServletRequest.class);
  2. HttpServletRequestrequestObj=(HttpServletRequest)requestCtrl.getMock();
  3. MockControlcontextCtrl=MockControl.createControl(ServletContext.class);
  4. finalServletContextcontextObj=(ServletContext)contextCtrl.getMock();
  5. MockControldispatcherCtrl=MockControl.createControl(RequestDispatcher.class);
  6. RequestDispatcherdispatcherObj=(RequestDispatcher)dispatcherCtrl.getMock();

按照doPost()的语句顺序,我们设定Mock 对象指定的行为:

Java代码 复制代码收藏代码
  1. requestObj.getParameter("username");
  2. requestCtrl.setReturnValue("admin",1);
  3. requestObj.getParameter("password");
  4. requestCtrl.setReturnValue("123456",1);
  5. contextObj.getNamedDispatcher("dispatcher");
  6. contextCtrl.setReturnValue(dispatcherObj,1);
  7. dispatcherObj.forward(requestObj,null);
  8. dispatcherCtrl.setVoidCallable(1);
  9. requestCtrl.replay();
  10. contextCtrl.replay();
  11. dispatcherCtrl.replay();

然后,测试doPost()方法,这里,为了让getServletContext()方法返回我们创建的ServletContext

Mock 对象,我们定义一个匿名类并覆写getServletContext()方法:

Java代码 复制代码收藏代码
  1. LoginServletservlet=newLoginServlet(){
  2. publicServletContextgetServletContext(){
  3. returncontextObj;
  4. }
  5. };
  6. servlet.doPost(requestObj,null);

最后,检查所有Mock 对象的状态:

Java代码 复制代码收藏代码
  1. requestCtrl.verify();
  2. contextCtrl.verify();
  3. dispatcherCtrl.verify();

运行JUnit,测试通过!

倘若LoginServlet 的代码有误, 例如, 将context.getNamedDispatcher("dispatcher") 误写为

context.getNamedDispatcher("dispatcher2"),则测试失败,JUnit 报告:

Java代码 复制代码收藏代码
  1. junit.framework.AssertionFailedError:
  2. UnexpectedmethodcallgetNamedDispatcher("dispatcher2"):
  3. getNamedDispatcher("dispatcher2"):expected:0,actual:1
  4. getNamedDispatcher("dispatcher"):expected:1,actual:0
  5. at...

完整的LoginServletTest 代码如下:

Java代码 复制代码收藏代码
  1. /**
  2. *LoginServletTest.java
  3. */
  4. packagecom.javaeedev.test.mock;
  5. importjavax.servlet.*;
  6. importjavax.servlet.http.*;
  7. importorg.easymock.*;
  8. importjunit.framework.TestCase;
  9. publicclassLoginServletTestextendsTestCase{
  10. publicvoidtestLoginFailed()throwsException{
  11. MockControlmc=MockControl.createControl(HttpServletRequest.class);
  12. HttpServletRequestrequest=(HttpServletRequest)mc.getMock();
  13. //setMockObjectbehavior:
  14. request.getParameter("username");
  15. mc.setReturnValue("admin",1);
  16. request.getParameter("password");
  17. mc.setReturnValue("1234",1);
  18. //ok,allbehaviorsareset!
  19. mc.replay();
  20. //nowstarttest:
  21. LoginServletservlet=newLoginServlet();
  22. try{
  23. servlet.doPost(request,null);
  24. fail("Notcaughtexception!");
  25. }catch(RuntimeExceptionre){
  26. assertEquals("Loginfailed.",re.getMessage());
  27. }
  28. //verify:
  29. mc.verify();
  30. }
  31. publicvoidtestLoginOK()throwsException{
  32. //createmock:
  33. MockControlrequestCtrl=MockControl.createControl(HttpServletRequest.class);
  34. HttpServletRequestrequestObj=(HttpServletRequest)requestCtrl.getMock();
  35. MockControlcontextCtrl=MockControl.createControl(ServletContext.class);
  36. finalServletContextcontextObj=(ServletContext)contextCtrl.getMock();
  37. MockControldispatcherCtrl=
  38. MockControl.createControl(RequestDispatcher.class);
  39. RequestDispatcherdispatcherObj=(RequestDispatcher)dispatcherCtrl.getMock();
  40. //setbehavior:
  41. requestObj.getParameter("username");
  42. requestCtrl.setReturnValue("admin",1);
  43. requestObj.getParameter("password");
  44. requestCtrl.setReturnValue("123456",1);
  45. contextObj.getNamedDispatcher("dispatcher");
  46. contextCtrl.setReturnValue(dispatcherObj,1);
  47. dispatcherObj.forward(requestObj,null);
  48. dispatcherCtrl.setVoidCallable(1);
  49. //done!
  50. requestCtrl.replay();
  51. contextCtrl.replay();
  52. dispatcherCtrl.replay();
  53. //test:
  54. LoginServletservlet=newLoginServlet(){
  55. publicServletContextgetServletContext(){
  56. returncontextObj;
  57. }
  58. };
  59. servlet.doPost(requestObj,null);
  60. //verify:
  61. requestCtrl.verify();
  62. contextCtrl.verify();
  63. dispatcherCtrl.verify();
  64. }
  65. }
分享到:
评论

相关推荐

    EasyMock的安装与部署所需全部文件.zip

    windows环境部署easymock,有用到的全部文件和安装说明,包换node.js,redis,mongdb,easymock源码

    5-Mock+EasyMock.rar

    个人作品 5-Mock+EasyMock.rar

    easymock-4.0-bundle

    手动的构造 Mock 对象会给开发人员带来额外的编码量,而且这些为创建 Mock 对象而编写的代码很有可能引入错误。目前,有许多开源项目对动态构建 Mock 对象提供了支持,这些项目能够根据现有的接口或类动态生成,这样...

    EasyMock单元测试例子

    几个例子展示如何使用EasyMock进行单元测试

    EasyMock

    NULL 博文链接:https://bruceliu02.iteye.com/blog/1775446

    模拟测试辅助工具easyMock.zip

    EasyMock 是一套通过简单的方法对于指定的接口或类生成 Mock 对象的类库,它能利用对接口或类的模拟来辅助单元测试。 Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较...

    easymock-4.2.jar

    EasyMock 是一套通过简单的方法对于指定的接口或类生成 Mock 对象的类库,它能利用对接口或类的模拟来辅助单元测试。 Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂...

    easymock的使用,含demo

    EasyMock 是一套通过简单的方法对于指定的接口或类生成 Mock 对象的类库,它能利用对接口或类的模拟来辅助单元测试。本文将对 EasyMock 的功能和原理进行介绍,并通过示例来说明如何使用 EasyMock 进行单元测试。 ...

    easyMock resource

    EasyMock + junit 实例

    easymock2.4+EasyMock使用简明手册.pdf

    easymock2 EasyMock使用简明手册

    EasyMock用到的objenesis

    EasyMock用到的objenesis

    EasyMock是一个可视化并且能快速生成模拟数据的持久化服务

    Easy Mock 是一个可视化,并且能快速生成 模拟数据 的持久化服务

    easymock

    easy mock for java

    EasyMock and PowerMock入门PPT

    什么时候需要Mock对象 什么是EasyMock EasyMock的优点和缺点 运行EasyMock需要的资源 EasyMock的基本使用步骤 什么是PowerMock 运行PowerMock需要的资源 PowerMock的扩展功能

    EasyMock 使用方法与原理剖析

    EasyMock单元测试的扩展; EasyMock简介(抽象类接口做测试); EasyMock来进行测试; EasyMock如何打桩; EasyMock实践指南;...EasyMock使用技巧;...EasyMock使用简明手册;...EasyMock使用说明;...用Mock object进行隔离测试;

    easyMock3.1

    它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。通过 EasyMock,我们可以方便的构造 Mock 对象从而使...

    EasyMock与Mockito 使用

    NULL 博文链接:https://zhangzhenting.iteye.com/blog/1829416

    EasyMock介绍及安装方法

    EasyMock 是一种模拟测试的框架,用于辅助模拟测试。当在测试过程中一些复杂的对象生成相当麻烦、费时或者根本无法生成时,可以用模拟的...原因是 EasyMock 在实现时为每个 class mock 对象提供了内建的以上三个方法。

    easymock2.4.zip

    easymock2.4 软件测试 mock

Global site tag (gtag.js) - Google Analytics