自动化回归测试含有外部依赖的应用程序 & 程序员的宿命

最近在研究一些其他的东西,所以一直没有准备这篇Blog,今天补上。^_^

我喜欢很快速很简单的说明事情,所以就不长篇大论了。是这样,我们都知道TDD的一大优点之一就是能够自动化回归测试,自动化回归测试的好处我想我这里就不用再叙说了,所以这篇文章的目的就是要讲如何编写自动化回归测试代码为有外部依赖的应用程序做测试。

当我们的代码必须依赖第三方事物的时候我们相应的测试工作就会加大难度与力度,比如当我们有数据库访问或者系统文件访问的时候。通常我们称这些第三方事物为环境,我们要为其增加很多测试用例,因为环境是会随部署到不同的地方而变的。头疼的是,作为一套好的测试用例,要为每种环境都搭配相应的测试用例,而困难在于如何营造这些测试环境。比如一个有数据库访问的程序,现在我要为它编写测试用例,按照老规矩,我需要制定Positive Test Case, Negative Test Case & Boundary Test Case,其中Negative Test Case就是测试如果数据库连不上,数据读不到等等的情况,这类的情况如何准备环境呢?不可能每次测试的时候将数据库断开吧?!面对种种类似的问题,很多人采取的态度就是不测试,或者只准备在大规模集成测试的时候再手动测试一遍。这样做有个坏处,那就是如果你的程序对异常情况没有处理好的话你只可能在大规模集成测试的时候才会发觉,而且这会消耗掉你非常多的时间去定位并解决它,因为已经过了很长时间了,没准依赖这段bug代码的代码已经有很多了,如果你的程序没有自动化回归测试的保护(可重构的)并且设计的依赖性较强的话那么你很可能会花上几个小时到几天的时间去解决一个当初可以在几分种内解决的bug。

所以众多优秀的程序员到最后还是选择了做测试(绝大多数还选择了做TDD^_^),这是程序员逃不了的宿命,不是为了增大自己的工作量,而相反是为了减少自己的工作量(与提高自身的效率)以及头疼量,当你为找不到bug的准确定位或解决它的可行办法而苦恼时。选择TDD的另外一个原因是因为它可以强迫你写出依赖较少的代码,从而达到优良设计的初衷。我不是在跟读者开玩笑,我想读者也听说过IoC或是Dependency Injection吧?没错,它们两个是同一个东西,一个OO设计原则,这个原则可以使你写出耦合性较弱的代码来,而因为TDD是测试先行,所以你会先写测试代码,在编写测试代码的同时你会很自然的应用这一原则,因为只当耦合性较弱的情况下Mock对象才有机会介入,从而很自然的在你的设计中运用了IoC。这部分有点深奥,况且我跑题了,以后再讲。

既然得出的结论是一定要测试,那么如何测试便自然是被众人所关注的了,突破点就在于如何不依赖环境而孤立的做测试,这也正是单元测试的意义所在。如果能做到不依赖环境的话,也就是说,测试环境全部由我们自己来在单元测试代码中营造,我们就可以摆脱测试难、难自动化的问题了,但是这也正是难点所在,怎么样在测试代码中完全营造测试环境呢?有人想出了好主意:“我们来模拟”,于是乎,Mock Objects出现了。当然mock这种东西早在不知道什么年代便已经有了,所以后人只是从其他行业把这个主意给借鉴了过来。

现在,在数据库的例子中,利用mock objects我们可以模仿数据提供者了(Data Providers),那么还有什么数据是我们不能得到的呢!;) 没错,我们就用mock objects来得到我们想要的返回结果,这样我们就成功的脱离了数据库这个外部环境了,同时我们还可以模拟数据库连接不上的情况(在mock object中抛出相应异常)。好,数据库访问的没有问题了,但是,如果程序依赖web server怎么办?笨,不会举一反三吗,当然是mock server了。不过注意只mock你真正需要的对象,不要mock出整个一个server,只要mock出和你要测试的部分息息相关的server部分就可以了。我记得以前的一个项目中的确还是被他们做了一个完整的mocked server,可以通过动态加载以及配置数据使mocked server可以返回测试想要的结果,不过个人不推荐这种做法,因为测试多了一层依赖,现在要依赖mocked server了。

好了,这篇Blog里就没什么好说的了,我想读者可能还没有看懂到底如何编写这段用mock实现隔离的测试代码,所以我预先准备了一个小示例项目,只有一个类,一个方法,详细等你下载了再看Readme.txt吧。^_^

https://files.cnblogs.com/cavingdeep/DbTestSample.zip

对了,在这个示例项目的测试覆盖率报表中你可以看到我核心部分(那个主要被测试的有数据访问的方法)的覆盖率是90%,其中没有覆盖到的10%我可是故意留出来的哦,给读者个机会,请把核心覆盖率提升至100%!;)

哦,对了,再补充一下,项目中的编译脚本是我送给大家的礼物,你绝对不会在网上找到类似的专门为各种项目而准备并且如此实用的比较灵活的NAnt脚本了。;)

posted @ 2005-08-18 16:07  Cavingdeep  阅读(3418)  评论(12编辑  收藏  举报