单元测试(三)-模拟对象

前面使用了桩对象来解除被测代码对外部的依赖,以便于独立地测试代码的内部逻辑。但桩对象只能测试系统的返回值或者状态的改变,如果要测试对象之间的交互,则需要使用模拟对象。

 

1 三种测试类型

a) 三种类型的测试分别为:

Value-based testing测试方法的返回值

State-based testing 测试状态的改变

Interaction testing 测试对象之间的交互

 

b) 交互测试测试的是某种特定的行为(如给另一个对象传递信息)。作者认为,交互测试应该尽量少用,在能使用值测试和状态测试的场合,就不要使用交互测试,因为交互测试会增加复杂度

 

c) 用自动给植物浇水的装置举例来说明状态测试与交互测试的区别:状态测试就是在一天结束后,通过查看土壤中的水分、植物的生长情况来测试浇水效果;而交互测试则要实时记录浇水次数、水量等信息。状态测试得出结论需要一定的过程和准备工作;但交互测试实施起来却不方便

 

d)  桩对象用于值测试和状态测试,模拟对象则用于交互测试

 

 

 

2 桩对象与模拟对象的区别

模拟对象是一种可以记录对自身调用情况的伪对象。模拟对象可用于交互测试,可认为是在桩对象的基础上,增加了记录调用情况的功能。它们之间的区别如下:

a) 桩对象(stub)替代被测代码对第三方对象的依赖,然后要针对被测代码进行断言

 

b) 模拟对象(mock)则模拟第三方依赖,然后为了判断被测代码是否与第三方依赖正确交互,要针对模拟对象进行断言

 

 

 

c) 模拟对象可以让测试失败,但桩对象不会

 

 

 

 

3 模拟对象的应用

a) 还是使用之前的LogAnalyzer类,假设业务场景为:当文件名称太短时,调用web服务发送信息。但web服务是外部依赖,web传输也比较费时,而且现在测试的是LogAnalyzer对web服务的调用行为(交互)。

LogAnalyzer如下

 

 

在测试代码中,将FakeWebService对象作为模拟对象传递给LogAnalyzer,并要针对FakeWebService对象进行断言。

 

 

在模拟对象中,属性LastError会记录上一次交互的内容以供断言

 

 

b) stub和mock有时需要同时使用,比如测试场景改为:调用WebService时可能会发生异常,如果有异常,则发送邮件给管理员,测试要做的是观察发送邮件行为是否正确。

LogAnalyzer比上一个的复杂

 

 

在测试代码中,FakeWebService作为桩对象,FakeEmailService作为模拟对象,首先设置FakeWebService要抛异常,最后针对FakeEmailService记录的邮件内容进行断言,测试LogAnalyzer与其的交互是否正确

 

 

可以设置FakeWebService是否要抛异常

 

 

FakeEmailService作为模拟对象,与上一个例子中FakeWebService的职责类似,记录交互信息以供断言

 

 

以上便是stub与mock的区别,以及mock的基本使用方法,在第二个例子中,同时使用了stub与mock,最后针对mock进行断言,这也是mock使用的基本原则,一个测试中最多只能有一个mock,其它都为stub;mock存在时便只对mock断言;在一个测试中只应该验证一件事,如果有多个mock意味着在测试不止一件事。

 

参考资料:

The Art of Unit Testing with examples in C#, 2nd Edition by Roy Osherove

 

转载于:https://my.oschina.net/u/2327858/blog/909272

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值