单元测试框架JMock与Mockito的用法比较

我们都有这种经验,测试在我们软件编码过程中占据了大部分时间,有时候觉得软件业务代码好写,但测试代码却难写了,单元测试是把自己的代码交托给测试同学和其他同学前的承诺。

为了获得更好的代码质量,我们一般都会用几好种工具,其中FindBugs和Emma(http://update.eclemma.org)就是常用的。

在测试与其它系统有交互的功能块,并且其它系统的稳定性未知的情况下,Mock就得派上用场了,否则测试起来极其吃力,并且效率低下。

下面简单介绍下两种Mock测试框架:JMock【http://www.jmock.org】和Mockito【http://www.mockito.org】。

一、前提说明

两个类:一个被Mock的对象(MayMockObject),一个被测试的对象(MainTstObject)。
很明显,我们的任务是测试MainTstObject,而该类引用了MayMockObject,为了测试的进行,我们模拟MayMockObject的实例。

测试用例类:MainTstObjectJMockTest和MainTstObjectMockitoTest。

二、依赖加入

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
    <version>4.4</version>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <scope>test</scope>
    <version>1.8.5</version>
</dependency>
<dependency>
    <groupId>jmock</groupId>
    <artifactId>jmock</artifactId>
    <scope>test</scope>
    <version>2.5.1</version>
</dependency>
 



当然,如果工程不是基于Maven构架的,可以直接加入相应的Jar也行。

三、外接接口(将被Mock的对象)

public interface MayMockObject {
    public String getString(String str);
}
 



四、功能类(被测试的类)

public class MainTstObject {
    private MayMockObject mayMockObject; // 引用了外接接口

    public String create(String str1, String str2) {
        return str1 + this.mayMockObject.getString(str2);
    }

    public void setMayMockObject(MayMockObject mayMockObject) {
        this.mayMockObject = mayMockObject;
    }
}
 



五、JMock的测试用例

public class MainTstObjectJMockTest {
    private Mockery       context = new JUnit4Mockery();

    private MayMockObject mayMockObject;
    private MainTstObject mainTstObject;

    @Before
    public void setUp() {
        this.mayMockObject = this.context.mock(MayMockObject.class); // Mock了外接接口

        this.mainTstObject = new MainTstObject();
        this.mainTstObject.setMayMockObject(this.mayMockObject);
    }

    @Test
    public void process() {
        final String str1 = "Mockito返回字符串。";
        final String str2 = "Mockito返回字符串。";

        this.context.checking(new Expectations() {
            {
                oneOf(mayMockObject).getString(str2);
                will(returnValue("")); // Mock返回值
               
                // allowing(mayMockObject).getString(with(any(String.class)));
                // will(returnValue(""));
            }
        });
       
        String ret = this.mainTstObject.create(str1, str2);
        Assert.assertEquals(ret, str1);
    }

    @After
    public void tearDown() {
    }
}
 



六、Mockito的测试用例

public class MainTstObjectMockitoTest {
    // 指定Mock的对象
    @Mock
    private MayMockObject mayMockObject;
   
    private MainTstObject mainTstObject;
   
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this); // 声明测试用例类
       
        this.mainTstObject = new MainTstObject();
        this.mainTstObject.setMayMockObject(this.mayMockObject);
    }
   
    @Test
    public void process() {
        String str1 = "Mockito返回字符串。";
        String str2 = "Mockito返回字符串。";
       
        Mockito.when(this.mayMockObject.getString(str2)).thenReturn(""); // Mock返回值
       
        String ret = this.mainTstObject.create(str1, str2);
        Assert.assertEquals(ret, str1);
    }
   
    @After
    public void tearDown(){
    }
}
 



七、最后

从两个测试用例可以看出,JMock和Mockito在用法上的一些区别:

1、对于要Mock的对象,JMock要显示指出来【this.mayMockObject = this.context.mock(MayMockObject.class);】;
    而Mockito只是简单加上注释【@Mock】,然后声明下测试用例类即可【MockitoAnnotations.initMocks(this);】。

2、对于方法的模拟,JMock显得更加复杂了【this.context.checking(new Expectations() {
        {
            oneOf(mayMockObject).getString(str2);
            will(returnValue(""));
        }
    });】
    而Mockito只要简单的一行代码就行【Mockito.when(this.mayMockObject.getString(str2)).thenReturn("");】。

从上可以看出,Mockito的代码行更少,更加简洁,个人比较喜欢用Mockito,简洁易记!

另外需要注意的是:JMock只能Mock接口,也就是上面的例子中【MayMockObject】只能为接口,不能为实体类;而Mockito就没有这个限制。
当然,我们既然用Mock,就是因为只知接口,而不知其具体实现,这样说来,JMock只能Mock接口不能算是Mockito的一个优点了。

===========================================
如有批评、指教、疑惑,请:obullxl@163.com
祝大家使用JAVA愉快!

 

同URL:http://hi.baidu.com/obullxl/blog/item/645bf5c4f17f8fa48226acef.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 针对这个需求规格说明,可以设计以下测试用例: - 客户为批发型企业,订货数大于 50,发货距离不超过 50 公里,应该有 15% 折扣 - 客户为批发型企业,订货数大于 50,发货距离超过 50 公里,应该有 10% 折扣 - 客户为非批发型企业,订货数大于 100,发货距离不超过 50 公里,应该有 10% 折扣 - 客户为非批发型企业,订货数大于 100,发货距离超过 50 公里,应该有 5% 折扣 - 客户为批发型企业,订货数不足 50,无折扣 - 客户为非批发型企业,订货数不足 100,无折扣 - 客户为批发型企业,发货距离超过 50 公里,无折扣 - 客户为非批发型企业,发货距离超过 50 公里,无折扣 2. 使用 JUnit 测试框架JMock 工具,可以编写以下测试代码: ```java import org.junit.Assert; import org.junit.Test; import org.jmock.Mockery; import org.jmock.Expectations; public class DiscountCalculatorTest { private Mockery context = new Mockery(); @Test public void testCalculateDiscount() { final FreightCalculator mockFreightCalculator = context.mock(FreightCalculator.class); // 设置桩模块,模拟计算运费的行为 context.checking(new Expectations() {{ allowing(mockFreightCalculator).calculateFreight(with(any(Order.class)))); will(returnValue(40.0)); }}); // 客户为批发型企业,订货数大于 50,发货距离不超过 50 公里,应该有 15% 折扣 double discount = DiscountCalculator.calculateDiscount(true, 60, mockFreightCalculator); Assert.assertEquals(0.15, discount, 0.0001); // 客户为批发型企业,订货数大于 50,发货距离超过 50 公里,应该有 10% 折扣 discount = DiscountCalculator.calculateDiscount(true, 60, mockFreightCalculator); Assert.assertEquals(0.1, discount, 0.0001); // 客户为非批发型企业,订货数大于 100,发货距离不超过 50 公里,应该有 10% 折扣 discount = DiscountCalculator.calculateDiscount(false, 120, mockFreightCalculator); Assert.assertEquals(0.1, discount, 0.0001); // 客户为非批发型企业,订货数大于 100,发货距离超过 50 公里,应该有 5% 折扣 discount = DiscountCalculator.calculateDiscount(false, 120, mockFreightCalculator); Assert.assertEquals(0.05, discount, 0.0001); // 客户为批发型企业,订货数不足 50,无折扣 discount = DiscountCalculator.calculateDiscount(true, 30, mockFreightCalculator); Assert.assertEquals(0, discount, 0.0001); // 客户为非批发型企业,订货数不足 100,无折扣 discount = DiscountCalculator.calculateDiscount(false, 80, mockFreightCalculator); Assert.assertEquals(0, discount, 0.0001); // 客户为批发型企业,发货距离超过 50 公里,无折扣 discount = DiscountCalculator.calculateDiscount(true, 60, mockFreightCalculator); Assert.assertEquals(0, discount, 0.0001); // 客户为非批发型企业,发货距离超过 50 公里,无折扣 discount = DiscountCalculator.calculateDiscount(false, 120, mockFreightCalculator); Assert.assertEquals(0, discount, 0.0001); // 验证桩模块的调用次数 context.assertIsSatisfied(); } } ``` 在测试代码中,我们使用 JMock 工具来模拟 FreightCalculator 类,并设置桩模块,模拟计算运费的行为。同时,我们针对不同的输入,通过 `assertEquals` 方法来验证输出结果是否符合预期。如果任意一个测试用例失败,那么测试框架会自动提示测试失败。通过编写这样的单元测试代码,开发者可以确保自己的业务逻辑代码在各种情况下都能够正确运行,并且与其他模块的协作也能够正确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值