ALL is Well!

敏捷是一条很长的路,摸索着前进着

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  30 随笔 :: 23 文章 :: 71 评论 :: 0 Trackbacks

jMock用法简介

总体上来说,jMock 是一个轻量级的模拟对象技术的实现。它具有以下特点:
1.可以用简单易行的方法定义模拟对象,无需破坏本来的代码结构表;
2.可以定义对象之间的交互,从而增强测试的稳定性;
3.可以集成到测试框架;
4.易扩充;

使用 jMock 模拟对象

我们首先必须引入 jMock 的类,定义我们的测试类,创建一个 Mockery 的对象用来代表上下文。上下文可以模拟出对象和对象的输出,并且还可以检测应用是否合法。

 

@SuppressWarnings("unchecked")
public class BookListTest {
    
private final Mockery context = new JUnit4Mockery() {
        
{
            
// 声明针对类进行mock,针对接口则会采用动态代理,不需要声明
            setImposteriser(ClassImposteriser.INSTANCE);
        }

    }
;
}


context 对象便可以用来创建Mock对象。
接下来的例子,我们模拟一个ServiceCall对象,我们以它的Map call(String target, Map dataMap)为例,针对此方法,设定预期值。然后我们在执行用例的时候调用此方法,便可以得到预期值。

@SuppressWarnings("unchecked")
public class BookListTest {
    
private final Mockery context = new JUnit4Mockery() {
        
{
            setImposteriser(ClassImposteriser.INSTANCE);
        }

    }
;

    @Test
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                one(sCall).call(JMockService.queryDtlInfo, 
null);
                
// 构建预期结果
                Map ret = new HashMap();
                ret.put(
"OrderId""9800000000");
                ret.put(
"Data"new ArrayList());
                
// 设定预期值
                will(returnValue(ret));
                
                
// 第二次被调用时,返回null
                one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                will(returnValue(
null));
            }

        }
);

        BookList bListAction 
= new BookList();
        bListAction.setName(
"jnbzwm");
        
// 设定ServiceCall对象为Mock对象
        bListAction.setServiceCall(sCall);

        
// 执行Action方法
        bListAction.execute();

        Assert.assertEquals(
"9800000000", bListAction.getOrderId());
        Assert.assertEquals(
0, bListAction.getDataList().size());
    }



校验expectations中的规则

使用jMock时,一般会通过如下代码指定expectations:

private final Mockery context = new JUnit4Mockery() {
        
{
            setImposteriser(ClassImposteriser.INSTANCE);
        }

    }
;

    @Test
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                one(sCall).call(JMockService.queryDtlInfo, 
null);
                
// 构建预期结果
                Map ret = new HashMap();
                ret.put(
"OrderId""9800000000");
                ret.put(
"Data"new ArrayList());
                
// 设定预期值
                will(returnValue(ret));
                
                
// 第二次被调用时,返回null
                one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                will(returnValue(
null));
            }

        }
);
        .
    }

}

为了校验expectations中的规则是否都满足,可以在测试完成后通过增加 context.assertIsSatisfied()方法来验证expectations是否满足。
如下代码:

    @Test
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                one(sCall).call(JMockService.queryDtlInfo, 
null);
                
// 构建预期结果
                Map ret = new HashMap();
                ret.put(
"OrderId""9800000000");
                ret.put(
"Data"new ArrayList());
                
// 设定预期值
                will(returnValue(ret));
                
                
// 第二次被调用时,返回null
                one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                will(returnValue(
null));
            }

        }
);

        BookList bListAction 
= new BookList();
        bListAction.setName(
"jnbzwm");
        
// 设定ServiceCall对象为Mock对象
        bListAction.setUpfServiceCall(sCall);

        
// 执行Action方法
        bListAction.execute();

        Assert.assertEquals(
"9800000000", bListAction.getOrderId());
        Assert.assertEquals(
0, bListAction.getDataList().size());
        context.assertIsSatisfied(); 
    }

由于我定义了两条规则,而第二条并未调用,所以此用例不会通过。

同一个方法连续调用时返回不同的值

有两种方法,第一种就是直接通过多次调用 will(returnValue(X))来指定。如:

    @Test
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                one(sCall).call(JMockService.queryDtlInfo, 
null);
                will(returnValue(
0));

                
// 第二次被调用时,返回1
                one(sCall).call(JMockService.queryDtlInfo, null);
                will(returnValue(
1));

                
// 第三次被调用时,返回2
                one(sCall).call(JMockService.queryDtlInfo, null);
                will(returnValue(
2));
            }

        }
);
        
    }

然而第一种方法会增加维护成本,且缺乏可控性。jMock提供了第二种方法,即通过onConsecutiveCalls的action来实现返回不同的返回值。如:

 

    @Test
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                atLeast(
1).of (sCall).call(JMockService.queryDtlInfo, null);
                will(onConsecutiveCalls( returnValue(
0),  returnValue(1),  returnValue(2))); 
            }

        }
);
        
    }



指定mock的方法抛出异常

在will方法中直接使用throwException的action。参考如下语法:

one(sCall).call(JMockService.queryDtlInfo, null);
// 设定预期值,抛出异常
will(throwException(new BusinessException("~", "name can't empty.")));

结合测试异常一起使用,代码如下:

    @Test(expected=BusinessException.class)
    
public void testExecuteNormal() throws Exception {
        
final ServiceCall sCall = context.mock(ServiceCall.class);
        context.checking(
new Expectations() {
            
{
                one(sCall).call(JMockService.queryDtlInfo, 
null);
                
// 构建预期结果
                Map ret = new HashMap();
                ret.put(
"OrderId""9800000000");
                ret.put(
"Data"new ArrayList());
                
// 设定预期值
                will(throwException(new BusinessException("~""name can't empty.")));

                
// 第二次被调用时,返回null
                one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                will(returnValue(
null));
            }

        }
);

        BookList bListAction 
= new BookList();
        bListAction.setName(
"");
        
// 设定ServiceCall对象为Mock对象
        bListAction.setUpfServiceCall(sCall);

        
// 执行Action方法
        bListAction.execute();
    }


posted on 2010-12-17 09:28 李 明 阅读(11989) 评论(3)  编辑  收藏 所属分类: JUnit

评论

# Nike Air Jordan 2010-12-17 10:16 Nike Air Jordan
看得迷迷糊糊的  回复  更多评论
  

# re: JUnit单元测试Mock技术之jMock用法介绍 2010-12-17 10:59 Ronaldo
@Nike Air Jordan
怎么迷糊了?  回复  更多评论
  

# re: JUnit单元测试Mock技术之jMock用法介绍 2016-07-18 15:14 pjl
JMockService是啥?  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: