[转载]打造第二代测试框架TestDriven 2.0(七)—— 让测试驱动更加的自动吧! – 美丽人生 – 博客园.
——————–
前 言 Preface
——————–
本 文介绍了一种新颖的测试思路,并制作了原型系统展示其效果。
此技术将作为测试驱动框架2.0的一个部分(Testdriven 2.0) 。
而 测试驱动2.0的目的是:让代码之间沟通,让变化更加容易。
——————–
测 试分类 与 本文的讨论对象 Catalog
——————–
测试包含了很多种, 每一种需要特定的技术去解决,例如:
1. Winform类的界面测试:通常使用钩子等Win32接口去捕捉用户的操作,然后模拟回放进行测试(此技术不在讨论范围)
2. Web界面测试:一般使用JS嵌入测试页面,同样模拟用户操作;或者使用IE内核等调用内部函数实现用户操作(此技术不讨论)
3. Web的Http模拟测试:在.net 2.0比较难实现,到了3.0之后的版本,微软对HttpContext这个庞然大物体做了重构,因此让测试变得稍微简单了。(此技术不讨论)
4. 类库、代码测试:这个是我需要讨论的终点,包含了各种框架、逻辑应用等。现有的技术主要是UNit / Testdriven.net / Mock等。他们也貌似很好的解决了一些问题。但是。。。
所以,本文接下来将针对第4种测试 (类库、代码测试),也是最常见的测试进行讨论。
———————
现有的问题 Problem
———————
现在的测试,很大一 部份是在回归。开发者梦想编写好自动测试代码,日后如果有变动,通过做回归,就知道是否破坏了之前的功能、是否产生了bug。朝着这个目标,诞生了很多测 试工具。可是在我看来,他们只是从一个小坑跳到了另外一个大坑。(也就是我之前说的,掉入自己挖的坑里了)
首先,测试的结 果是否准确,完全取决于测试数据是否全面准确。 那么编写测试数据本身就存在了人为的bug。
其次,测试代码和业务代码紧 密联系,一旦业务代码修改,测试代码往往是全盘否定的。这就出现一个矛盾:如果测试代码写的马虎,日后基本上不能用;如果测试代码写的精细,一旦修改起 来,之前的工作都白费了。
所以,我们真正期望的是:能够自动分析业务代码,自动编写测试代码, 而不是人去写。这个目标现在还很难实现(微软在VS2010里面已经大量引入了Code Gen等技术,可是。。)
可 是难,不等于不行,下面我将尝试迈出一小步。
———————
原理分析 Analysis
———————
要 让测试变得自动,首先需要抽象出测试过程,然后逐一攻破。经过我分析,一段测试代码主要包含了三个方面:
1. 测试数据生成。
直 接决定了测试代码是否有效;因此要求全面、准确、也业务逻辑精密绑定。 这部分工作目前是没有更好的思路。
2. 调用对应方法。
这个很简单,就是调用一个方法,传入测试数据。没有优化的必要。
3. 查看测试结果是否符合预期。
这部分以往是写这非常无聊的Assert.IsEqual等。既无聊,又浪费时间。而恰恰这部分我发现了提升的 空间。
测试结果无非就是字符串、对象等。就是C#的ValueType / class。 而如果是对象,也一定是对象的某些属性(Property) 。而这些数据都是可以被序列化、反序列化的!
因 此 这个过程完全可以被机器代替,从而让测试代码变得更加灵活,立马减少50%的工作量!现在我就展示一下目前的原型系统效果。
———————
原 型系统效果 ProtoType
———————
首先是一段测试代 码。
{
object pojo = CreatePojo();
Assert.SaveOrVerify(
“test000 create pojo“, pojo);}
这 段代码的目的是 测试生成的pojo对象是否符合预期。 而一个Pojo对象可能是下面一个接口的实例:
{
byte[] Image { get;set;}
string Name { get;set;}
double Fee { get;set;}
int Age { get;set;}
IinterfaceWithAllCollection[] pojos { get;set;}
List<IinterfaceWithAllCollection> pojos2 { get;set;}
ObjectWithValue objPojo { get;set;}
ObjectWithValue[] objPojos { get;set;}
List<ObjectWithValue> objPojos2 { get;set;}
}
按照以往的做法,一定是要展开这个对象,获 取每一个属性,然后做Assert。现在我仅仅需要一句话就完成了测试 结果验证:
Assert.SaveOrVerify(“test000 create pojo“, pojo);
不 知道您感受到了其中的魅力和惊喜没有?
调用了这句话, 框架首先会搜索保存在磁盘的结果数据,一般是xml文件;这些数据本质上就是预期结果的序列化值。然后逐一和这些值做对比。
那 么您一定好奇,这些期望的值从哪里来?答案就是,代码本身生成。当第一次执行的时候,是没有预期值的,那么框架会给出警告,然后将当前数据持久到磁盘。例 如:
Verifying IinterfaceWithAllCollection.Image.
TRUE: expected=%01, actual=%01
Verifying IinterfaceWithAllCollection.Name.
TRUE: expected
Verifying IinterfaceWithAllCollection.Fee.
。。。。。 省 略
这个时候,我调用一个配置界面,就可以查看第一次生成的 值,然后修改成为预期值:
这 样一个序列化结构就可以通过 树形结构 展示出来。 现在我们只要查看第一次运行的结果是否正确,调整ExpectedValue。 这样这段测试代码就可以永远被重复调用了。
———————-
小 结 Summary
———————-
因为是原型系统,目前还不能发出第 一个release,不过很快就可以完成了。主要是我写的代码和屎一样烂,需要进行优化才好意思拿出来。
等release 出来时候,所有代码都会采取开源的策略。不过是一种新的开源策略。
如果各位有急着需要的,咱们可以相互讨论交流下。希望大 家多提供些思路,多提供您期望的需求。谢谢!
我们的最新动态 (Bamboo@pixysoft.net)
- 1.DynamicProxy开发完成.和微软的Realproxy比较.性能提高1.5倍… [2010-6-5]
- 2.对象反序列化的emit框架完成.性能测试提高了15倍.[2010-6-4]
- 3. 对象序列化操作使用最新的emit框架.动态编译.性能提高了10倍…[2010-6-3]