免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1925 | 回复: 0

终结DbHelper鬼画符 Tdd全攻略 [复制链接]

论坛徽章:
0
发表于 2011-03-07 15:06 |显示全部楼层
转:玄歌

   终结DbHelper鬼画符 Tdd全攻略




   我们现在开始为Db增加三个构造方法,这里会详细的演示Tdd的3个重要的要素:测试先行、代码复审、重构。

   我们先解释一下为什么要先写测试,再写代码,实际上,有下面的七个方面的好处:

   1、关注点集中

   2、单一的成功被无数成功取代,心态将更为良好:脑力工作,情绪是非常重要的,大家如果正常的统计自己的有效工作时间,往往会发现自己一天的有效工作状态持续时间非常短。一个很经典的说法,是多数程序员每天正常工作的时间平均下来不超过一个小时。

   3、占在类的用户角度,来看待类的设计,有助于

   4、建立起整个项目的质量基础

   5、累积下来的单元测试,是后期代码修改的准则

   6、Bug的修复将更为精准。

   7、单元测试,就是团队中其他程序员的使用手册。

   一鱼六吃,这样的事情,为什么不做?



    代码复查,简单的说就是逐行阅读代码,从而找出潜在的问题和代码结构上的坏味道。据说,代码复查能够发现项目中一半以上的Bug,当然,在代码尚未发布、或者Bug尚未转移到团队其他成员处的时候,修复Bug的成本是最低的。

    代码复查是很枯燥的工作,自己复查、团队成员交互复查都行。敏捷方法中比较极端的例子是双人编程,这样,实际上代码复查贯穿于整个开发时间。



    重构,消除代码中坏的味道,这里最常见的一种现象是“重复的代码”。

    由于有大量的单元测试,重构过程中保持全部单元测试通过,有助于实现我们的目标:仅仅调整代码的结构,而不会令功能实现上出现问题。

    代码质量,并不是代码工作如何精准,而是代码的结构是否做到了最简化。请注意,稍稍不留意,代码增加的少许复杂性,会令同事阅读困难、甚至令自己阅读困难,各处的复杂性累积之后,会造成Bug数量的大幅增长,维护也变得困难。这里可以参考用户体验的一句名言“多一次击键,用户可能永远不会使用这项功能”。

    唠叨完毕,我们先做好准备。

    我们创建一个单元测试项目,引用我们的工作项目Faster.Data类库项目。在单元测试项目中增加一个配置文件App.config,我们将数据库连接信息保存在这个配置文件中。

    单元测试中最常见的问题,是“数据库如何测试?”

   我曾经饶有兴趣的使用Mock,但最终对自己定下了规矩,即今后绝不使用任何Mock。原因:Mock对象会大幅增加单元测试的简洁性,构建Mock对象有时候也需要大量的工作,充满了Mock的单元测试可读性很差,团队成员需要全体掌握相关的知识从而导致对开发人员的门槛提高,这也意味着成本的提高。

    不过,在这个类库创建完毕后,数据库读写操作就有了很好的基础,今后所有应用项目则根本无需对数据库读写进行单元测试。

     我的方法是,建立测试数据库,保证数据库所有表格处于空白的无记录状态,即针对每一项测试,测试前要准备数据,测试后毁尸灭迹。

    那么,现在开始为Db增加构造方法,我们先做最原始的:

    第一步 在类图中为Db添加一个构造方法 Db(string connectionString,string providerName)



    为什么先做这个?因为这是与配置文件无关的,Db(string configName),这个从配置文件中获取上述两个参数,Db()则默认的使用ApplicationServices配置项获取上述两个参数。我们显然要先做最简单的。换句话说:先解决构造问题,再解决配置文件的问题。

    第二步,切换到这个构造方法的代码,右键,选择创建单元测试。此时,Ide帮我们在下是项目中增加了一个代码文件,测试类的名称为DbTest,嗯,类名加上Test。

    那么,这是第一个基本的概念,测试是以类为单位的,每一个待测试的类,对应一个测试类。多数情况下,类的每一个public成员,对应一个测试方法。我们要牢记两点:1、不针对私有成员写测试;2、每一个测试方法都要足够的简单,突出该方法的目的。

     第三步,我们在测试方法中,写上这样的代码

     Db db= new ("连接字符串","提供者名称");

     Assert.IsNotNull(db);  //我们期望上一行创建的db对象不为空

     第四步,运行测试,出现绿色的“成功”提示。好,现在这个测试已经通过。

     第五步,现在我们要确定Db已经正常的连接到数据库。对,如您所说,Db的State状态必须为Open

     我们在测试方法下,再增加一行

     Assert.AreEqual(ConnectionState.Open,Db.State);//期望创建的连接已经打开

     运行测试,当然失败了,因为我们还没有做真正的连接工作。

    第六步,我们为刚刚写的Db的构造方法中增加如下的代码:

factory = DbProviderFactories.GetFactory(provider);            
connection = factory.CreateConnection();
connection.ConnectionString =connectionString;
connection.Open();


    第七步,运行测试,通过。嗯,现在这项工作完成。

    按照同样的方式,创建其他两个构造方法。比如:

    第八步:从某个配置项中定义的连接字符串,创建连接

var setting = ConfigurationManager.ConnectionStrings[config];

factory = DbProviderFactories.GetFactory(provider);            
connection = factory.CreateConnection();
connection.ConnectionString =connectionString;
connection.Open();

    第九步 重构

    我们简单的审阅代码,会发现第六步和第八步的代码,显然有多数重复。那么,创建一个私有方法CreateConnection,包含如下代码:

factory = DbProviderFactories.GetFactory(provider);            
connection = factory.CreateConnection();
connection.ConnectionString =connectionString;

然后,第六步的代码便是:

CreateConnection(connectionString, provider);

第八步的代码变为:

var setting = ConfigurationManager.ConnectionStrings[config];
CreateConnection(setting.ConnectionString, setting.ProviderName);


重复,是最常见的“坏味道”,这里是最浅显的例子。

如此,我们通过创建三个单元测试、从而创建三个构造方法,完成了这一组任务。过程中,根据进度,在Tfs团队项目中将各项task的状态分别由in progress 改为done。

看看,比较满意吧?运行所有测试,通过。相关的任务,done。将代码签入到源代码服务器,接着做剩下的其他工作…
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP