JMock使用入门

来源:互联网 发布:历代超人知乎 编辑:程序博客网 时间:2024/06/05 17:52

【IT168 技术文章】

    JMock是一个使用模拟对象机制测试Java代码的开发包。模拟对象(Mock Object)可以取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能,模拟对象的背后目的就是创建一个轻量级的、可控制的对象来代替测试中需要的真实对象,模拟真实对象的行为和功能,方便我们的测试。JMock就是这种机制的实现,使用JMock我们可以快速创建模拟对象,定义交互过程中的约束条件等,同时JMock也是易扩展的,你可以很方便添加自定义的需求。下面就让我们看看如何去使用JMock。

    现在的系统都是面向接口设计的,在系统中我们主要围绕接口实现进行编程。我的一段测试代码中需要使用一个接口的方法,这个接口是由我的同事开发的,他还未完成这个接口实现,这是我就需要模拟一个接口的实现来保证我的测试、功能实现顺利进行下去。这里接口的代码如下:
 
public interface UserDao
{
public String getUserName(Integer id);
}

    在一个TestCase中,我们包含以下测试方法:

public void testGetName() throws Exception
{
//1创建一个模拟对象,将实际需要的对象类型和模拟对象进行关联
Mock mock = new Mock(UserDao.class);
UserDao userDao = (UserDao) mock.proxy();
//2 设置欲调用函数模拟实现的具体信息:名称、参数和返回值
String methodName = "getName";
Integer userId = new Integer(1);
String userName = "Jacky";
//3 设置模拟对象的行为方式
mock.expects(new InvokeOnceMatcher()). //设置期望,我们将调用某个函数,InvokeOnceMatcher表示仅调用一次该方法
method("getName"). //欲调用的函数名
with(new IsEqual(userId)). //函数的参数
will(new ReturnStub(userName)); //期望的返回值
System.out.println(userDao.getName(userId)); //完成实际需求对象的方法调用
}
 
    在以上代码中,我们通过三个步骤完成模拟对象的操作实现。步骤1我们创建一个模拟对象,并与实际对象类型进行关联。步骤2我们将模拟实际对象的函数操作环境,这里我们设置函数名称、参数和期望返回值。步骤3中我们在模拟对象上完成我们的期望实现,如调用实际对象的方法应该返回指定的返回值等,最后我们就可以调用实际类型的对象啦。

    我们对模拟对象的要求主要集中在方法的调用和返回值,所以许多操作都是围绕这方面进行的,下面我们看看JMock的这方面的实现机制,如何在模拟对象上设置期望以达到实际的效果。

    Mock是我们要模拟的对象,它需要一个欲模拟的实际对象的类型,这里可以为接口或具体类(需要使用cglib)。模拟对象创建完毕后,我就要设置我们的期望,主要是针对函数的。在JMock中设置期望可以通过expects和stubs来实现,关于这两者的区别,大家可以参考一些文档,不过有一点就是Expection比stub有更多的约束条件(调用次数方面)。这里我们通过Mock的expects函数来实现期望, expects接受InvocationMatcher对象,主要是调用的匹配规则,如仅调用一次、调用多次或不调用等。expects的返回值为NameMatchBuilder,我们需要设定函数名称,我们通过method方法来指定函数名。method的返回值为ArgumentsMatchBuilder,这时我们需要设定该函数的参数约束信息,如果没有设置,表示匹配任何参数,设置参数的约束条件,可以通过with函数进行操作,该函数接受的参数其实也就是实际调用中对象的函数参数,在这里我们只是设定约束条件,如实际调用时的函数参数应和这里的参数相同、相等或类型相同等。如实际函数的声明如下getName(Integer para1,Integer para2),那么对应的with函数即可为with(new Constraint(para1Value),new Constraint(para2Value)),这样就可以保证参数约束的启用。with函数的返回值为MatchBuilder,这时我们可以设定我们希望的返回值,通过will函数就可以完成。这里函数,参数和返回值确定了一个匹配的原则,当模拟对象进行操作时,它需要找到对应的匹配,这样操作才能进行下去。此时我们就完成了在模拟对象上的一个期望实现。

    JMock的设计思想非常好,这里其实就是以一个简单的实际例子来讲解,更多关于JMock的信息和功能你需要参考JMock的说明文档。在实际的测试过程中,我们还是要尽量避免使用模拟对象,毕竟我们要花费不少精力去模拟一个实际对象。如在Web开发过程中,不少人将HttpServletRequest作为函数参数,这本身不是什么问题,但是在测试方面讲,这有点麻烦,模拟一个能实现HttpServletRequest所有功能的类比较复杂,牵涉到web容器的方方面面,这里我们可以通过JMock来实现一个HttpServletRequest模拟对象,实现我们关心的一些方法,但是这不是上策。所以我们在设计的时候同时要考虑到测试,如果讲这两方面整合起来,对你的开发效率会有很大的提高。

    总结:JMock的便捷性和思想非常好,上面我们的例子牵涉到许多类和方方面面,如果你的TestCase为JMock的MockObjectTestCase,那么你就方便多啦,MockObjectTestCase提供了许多方便的函数,简化我们的编码。关于模拟对象的使用,更多的是要从你的开发和经验中来,掌握好Mock将给你的测试带来意想不到的便捷。
 
    提示:JMock的使用非常简单,但是如果要使用JMock更多功能,应该理解以下几个方面:Expection和Stub的区别,Constraints和Matchers,这将非常有助于你更好地使用JMock。

原创粉丝点击