打造第二代测试框架TestDriven 2.0(六)—— 最新测试思路分析

------------------ 

前言 Preface

------------------ 

这几天正在做dynamic的时候,突然想到了测试框架的最新思路。

------------------ 

思路介绍

------------------ 

整个测试流程主要是:给出测试数据,查看符合的结果。

测试种类非常多,例如CS界面测试(使用钩子等录制并回滚);BS界面测试(使用js直接调用) ;网站的测试(模拟http);普通类库测试(NUnit等)等等。

如果是界面这种黑盒测试,我就不讨论;网站测试难度很大,应该尽量化简为类库测试;所以最终来到普通来库测试。

因此一个非常典型的测试代码如下:

代码
        public void test011()
        {
            ObjectWithInterfaceCollection pojo4 
= new ObjectWithInterfaceCollection();
            pojo4.Age 
= 321;
            pojo4.Fee 
= 321.321;
            pojo4.Name 
= "pojo";
            pojo4.Type 
= EnumTYpe.B;

            ObjectWithInterfaceCollection subpojo 
= new ObjectWithInterfaceCollection();
            subpojo.Age 
= 456;
            subpojo.Pojo 
= new ObjectWithCollecton();
            subpojo.Pojo.Age 
= 789;

            pojo4.Pojos 
= new ObjectWithCollecton[] { subpojo };

            pojo4.Pojo 
= subpojo;

            pojo4.Ipojolist 
= new List<IinterfaceWithValue>();
            pojo4.Ipojolist.Add(subpojo);

            pojo4.Ipojo 
= subpojo;

            IXmlNode node 
= XmlManager.DynamicSerialize(pojo4);

            ObjectWithInterfaceCollection rpojo4 
= XmlManager.DynamicDeserialize<ObjectWithInterfaceCollection>(node.Serialize(true));

            Assert.IsEqual(pojo4.Age, rpojo4.Age);
            Assert.IsEqual(pojo4.Fee, rpojo4.Fee);
            Assert.IsEqual(pojo4.Name, rpojo4.Name);
            Assert.IsEqual(pojo4.Type, rpojo4.Type);

            Assert.IsEqual(pojo4.Pojos[
0].Age, rpojo4.Pojos[0].Age);
            Assert.IsEqual(pojo4.Pojos[
0].Pojo.Age, rpojo4.Pojos[0].Pojo.Age);

            Assert.IsEqual(pojo4.Pojo.Age, rpojo4.Pojo.Age);
            Assert.IsEqual(pojo4.Pojo.Pojo.Age, rpojo4.Pojo.Pojo.Age);

            Assert.IsEqual(pojo4.Ipojolist[
0].Age, rpojo4.Ipojolist[0].Age);

            Assert.IsEqual(pojo4.Ipojo.Age, rpojo4.Ipojo.Age);

            Assert.Write(node.Serialize(
true));
        }

现在的测试存在的问题: 

1. 由于测试代码和逻辑代码相互关联非常紧密;一旦逻辑代码变动,导致测试代码变动的非常厉害,甚至要重写。

2. 测试代码如果书写不认真,那么在第一个问题上就会问题加重;可是如果写测试代码也使用了重构、设计模式,这样工作量倍增,一旦逻辑代码变动,测试代码变得没有意义。

可见,如果要使用测试驱动,那么带来的问题是非常多的。

测试驱动能解决的问题是:

1. 通过回归测试,能够知道新开发的功能有没有违反原有的功能。

貌似测试驱动能解决的问题和带来的问题相比较,微不足道。

因为测试的正确取决与输入参数的正确和全面。可是如果对测试代码马虎对待,那么结果一定也有问题。这样导致了回归测试出现错误。产生一个恶性循环。所以到目前为止,我还没想到一个好的思路。不过有点转机。

由于测试代码是逻辑代码的辅助代码,从理论上,逻辑代码变更后,测试代码应该非常容易变更。而目前无法做到,原因是,对整个测试流程无法抽象出一个简单的模型。我现在就尝试抽象。

上文的代码包含了:

1. 生成测试数据

复杂、烦琐、而且重要。测试数据直接决定了本测试结果是否有效。因此这部分一定需要人去写。

测试数据本身一定也是POJO对象(参考3);同时测试中,必须可见方便维护和分析。

2. 调用对应的方法

简单,仅仅一句话。完全可以机器代替,所以问题在于手写一个调用快,还是鼠标指定一个调用快。
 

3. 查看测试数据是否符合期望。 

工作量烦琐,而且毫无意义,所以很多人喜欢用console.write,但是这样又丢失了机器检测的优势。导致人为错误。 

可是分析发现,测试数据一定是对象,例如string, 如果是类的对象,则一定需要继续展开,查看这个类的属性;因此可以看成是一个典型的POJO模型。

如果有一种机制,能够对POJO进行展开和检查,而且不需要人为参与,那么就降低了很多工作量。

唯一需要人为参与的地方,就是规定出某个变量 = XXXX / is null / throw exception. 这个规定的过程,可以抽象出来一种机制。

根据分析,那么到底是使用IDE工具?还是使用代码?

从程序员角度分析,使用代码>使用鼠标+键盘输入。!!

结论:尽量使用代码。

数据输入使用界面还是代码? 

如果使用界面,那么接下来的也要界面。非常麻烦。仅仅制定一个对象,可能需要写一堆xml

结论:使用代码。

结果验证使用界面还是代码?

结果验证的时候,第一次需要配置验证,可以参考noebe.global的思路,自动对输出进行截取+编译为xml,给出界面用户指定数据校验。

之后如果再运行,就可以查看是否和第一次制定的一致。类似的效果:

结论:Assert.Verify(object value); <---- 一句话就把所有结果都验证了。

配置的文件放在什么地方? 

放在项目的目录中。可以使用codelive.visual,也可以直接操作目录。目前第一个开放版本使用file。不集成在IDE。

依赖性到底如何?

1. 是否使用reflection? 如果不使用,那么就用reflection。这样可以不依赖reflection的dll

2. 是否使用config?如果不进行序列化等操作,可以不用——》必须建立一个可以在核心框架解析的语法,例如:

xxx.xxx.xxx = xxx;

如果这2个问题解决了,那么整个Assert.Verify可以脱离framework直接运行。

小结一下:

之前所有代码都不变,例如attribute之类的。可以使用自己的,也可以使用testdriven的。

然后来到验证的时候,首先获取当前method的一个id,作为搜索;

如果发现文档不存在,则抛出异常。用户可以调用Assert.Save()创建一个验证文档。这个时候将递归获取所有数据。

搜索到验证文档后,开始解析 并对比值是否正确。 

原文地址:https://www.cnblogs.com/zc22/p/1753562.html