.NET 虚拟框架(Mock Framework)原理剖析
2017-02-22 22:21
246 查看
什么是虚拟框架?它实际上是一种用于方便单元测试用途的测试框架 在Nuget上面这类虚拟框架挺多的 推荐一些流行的虚拟框架如Moq、NMock2、Typemock等。
那么简单的先了解一些测试驱动的概念
BDD(行为驱动测试)
BDD的目标是任何系统之间的关联者中定义可以促进最终产品交互的循环互动(统一语言) 它的一大理念是从每个互动中得到定义明确的行为 同时它包含三个核心部分即明确的 前置条件、动作和输出
TDD(测试驱动开发)
TDD是一个引导开发者从测试开始写代码的流程 对于每个类或方法而言 TDD的开发者从一个期望行为的测试开发 测试最初是失败的 但后期慢慢迭代添加方法或代码 使测试通过(敏捷开发学)
那么虚拟框架听上去似乎很复杂 但从原理上它并不复杂 当然它的确可以阻碍大量开发人员 写这类的东西门槛会稍微高一些
虚拟框架在单元测试中主要用于虚拟一个被测试或用于关注依赖处理的对象 它实际上是仿冒对象(fake object)的一种扩充
仿冒对象它是什么类型的一种工作原理?
从上述代码中你可以看到仿冒对象需要进行繁琐的硬编码 同时在测试时我们无法尽可能地关注被测试的代码本身
虽然它的确可以收集被测代码依赖了我们输入的仿冒对象那些成员 在某个动机下它调用了我们什么成员 达到某种行为 最后它输出什么值 但你不认为这非常繁琐?
当然现在进行测试基本是白盒测试而不是黑盒测试(除非你利用了第三方非开源代码的类库)假设一直让人去测试一些他们所预设的测试条件 而测试结果告诉你代码永远不会出现问题 那是一种多么愚蠢的行为 可能运行时它可能会恰好出了问题 作为测试与开发人员应尽可能考虑代码边界问题
这种问题与1996年Ariadne 5火箭工程项目发生的问题有异曲同工之处 一个价值67亿美元的工程项目难道在发射前不会经历各种类型测试 如OA质量审核、集成测试、验收测试、大量的单元测试、很高的ROI值?
它不可能盲目的发射一个价值67美元的火箭、它们出现问题就在于反复测试告诉人们永远不出问题 但恰恰就出现了一个数值溢出的异常但还是通报了上层模块 让上层模块认为现在可以启动脱离火箭了 所以这个项目从起飞到结束只经历了40秒就自动分解了 这不是就是对永远不可能出问题的测试结果的一种讽刺?
上面提到虚拟框架是对仿冒对象进行的一种扩充与升级 两者的原理完全相同为被测试代码对象提供一个抽象依赖并把它输入到被测试对象中 关注它们的相互交互的行为达到测试目的 但唯一不同的是虚拟框架或动态生一伪对象或者说仿冒对象 并把它的行为代理给需要测试方进行测试
从上图中我们看到一张用于测试调用者依赖了IFoo那种成员它期望得出什么结果 从IFoo这个依赖中得出什么结果 MockFoo是我们用于关注被测调用方 调用方调用了IFoo::Say的函数 它希望告诉MokeFoo你需要做一个说的行为
那么如果我们在把行为提交给Foo看看它会提供什么答复 或者反复伪造测试数据返回给调用方看看它会出现
什么问题 它处理的结果有没有符合预期等等 这是对这类型测试中的一种方式进行简单说明
上面已经提到把需要输入到被测试代码或对象中接口依赖进行仿冒 那么虚拟框架就是对这个接口依赖进行动态
接口代理 面向抽象可以提高可测试性 这从一开始就不是闹着玩的 不过不要过渡抽象(适度恰到好处最优)在编写时参考相应的指导性
原则、向量原则、可测试性原则(可见性、控制性、简约性)、可读性3C原则(一致性、清晰性、注解)等等。
对于接口动态代理方面的博客可以参考的 http://blog.csdn.net/liulilittle/article/details/54342457 这篇文章内的内容
不写了手太疼了。
那么简单的先了解一些测试驱动的概念
BDD(行为驱动测试)
BDD的目标是任何系统之间的关联者中定义可以促进最终产品交互的循环互动(统一语言) 它的一大理念是从每个互动中得到定义明确的行为 同时它包含三个核心部分即明确的 前置条件、动作和输出
TDD(测试驱动开发)
TDD是一个引导开发者从测试开始写代码的流程 对于每个类或方法而言 TDD的开发者从一个期望行为的测试开发 测试最初是失败的 但后期慢慢迭代添加方法或代码 使测试通过(敏捷开发学)
那么虚拟框架听上去似乎很复杂 但从原理上它并不复杂 当然它的确可以阻碍大量开发人员 写这类的东西门槛会稍微高一些
虚拟框架在单元测试中主要用于虚拟一个被测试或用于关注依赖处理的对象 它实际上是仿冒对象(fake object)的一种扩充
仿冒对象它是什么类型的一种工作原理?
public interface IFoo { void Say(); } public class Foo : IFoo { void IFoo.Say() { Console.WriteLine("say"); } } public class FakeFoo : IFoo { private IFoo foo = new Foo(); void IFoo.Say() { foo.Say(); } }
从上述代码中你可以看到仿冒对象需要进行繁琐的硬编码 同时在测试时我们无法尽可能地关注被测试的代码本身
虽然它的确可以收集被测代码依赖了我们输入的仿冒对象那些成员 在某个动机下它调用了我们什么成员 达到某种行为 最后它输出什么值 但你不认为这非常繁琐?
当然现在进行测试基本是白盒测试而不是黑盒测试(除非你利用了第三方非开源代码的类库)假设一直让人去测试一些他们所预设的测试条件 而测试结果告诉你代码永远不会出现问题 那是一种多么愚蠢的行为 可能运行时它可能会恰好出了问题 作为测试与开发人员应尽可能考虑代码边界问题
这种问题与1996年Ariadne 5火箭工程项目发生的问题有异曲同工之处 一个价值67亿美元的工程项目难道在发射前不会经历各种类型测试 如OA质量审核、集成测试、验收测试、大量的单元测试、很高的ROI值?
它不可能盲目的发射一个价值67美元的火箭、它们出现问题就在于反复测试告诉人们永远不出问题 但恰恰就出现了一个数值溢出的异常但还是通报了上层模块 让上层模块认为现在可以启动脱离火箭了 所以这个项目从起飞到结束只经历了40秒就自动分解了 这不是就是对永远不可能出问题的测试结果的一种讽刺?
上面提到虚拟框架是对仿冒对象进行的一种扩充与升级 两者的原理完全相同为被测试代码对象提供一个抽象依赖并把它输入到被测试对象中 关注它们的相互交互的行为达到测试目的 但唯一不同的是虚拟框架或动态生一伪对象或者说仿冒对象 并把它的行为代理给需要测试方进行测试
从上图中我们看到一张用于测试调用者依赖了IFoo那种成员它期望得出什么结果 从IFoo这个依赖中得出什么结果 MockFoo是我们用于关注被测调用方 调用方调用了IFoo::Say的函数 它希望告诉MokeFoo你需要做一个说的行为
那么如果我们在把行为提交给Foo看看它会提供什么答复 或者反复伪造测试数据返回给调用方看看它会出现
什么问题 它处理的结果有没有符合预期等等 这是对这类型测试中的一种方式进行简单说明
上面已经提到把需要输入到被测试代码或对象中接口依赖进行仿冒 那么虚拟框架就是对这个接口依赖进行动态
接口代理 面向抽象可以提高可测试性 这从一开始就不是闹着玩的 不过不要过渡抽象(适度恰到好处最优)在编写时参考相应的指导性
原则、向量原则、可测试性原则(可见性、控制性、简约性)、可读性3C原则(一致性、清晰性、注解)等等。
对于接口动态代理方面的博客可以参考的 http://blog.csdn.net/liulilittle/article/details/54342457 这篇文章内的内容
不写了手太疼了。
相关文章推荐
- .Net 虚拟框架的实现原理
- 解读.Net虚拟框架的实现原理
- 一起谈.NET技术,NHibernate3剖析:Mapping篇之ConfORM实战(2):原理
- [原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略
- .Net中如何操作IIS的虚拟目录原理分析及实现方案
- [原创] WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- 从N层到.NET详细剖析原理(2)
- 一个高性能RPC框架原理剖析
- 孙鑫vc++ 第三课 MFC AppWizard的原理与MFC程序框架的剖析
- .Net中如何操作IIS的虚拟目录原理分析及实现方案
- [原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略
- 通用.Net平台系统框架剖析与设计(简单概括)
- 解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
- 深入解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
- 一个高性能RPC框架原理剖析
- 从N层到.NET详细剖析原理(1)
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
- Struts1.3框架原理剖析(二)
- android自动化框架简要剖析(一):运行原理+基本框架