现在的位置: 首页 > 综合 > 正文

零雨其蒙:Practicing Test-Driven Development by Example Using Delphi

2013年06月19日 ⁄ 综合 ⁄ 共 2904字 ⁄ 字号 评论关闭

Practicing Test-Driven Development by Example Using Delphi

                    零雨其蒙原创 转载请注明

1       测试驱动开发

测试驱动开发不是什么噱头,而是真正有用的开发实践。今天派给我一个任务,让我解决一下退休提醒功能的Bug,我没看出原来的代码有何错误,不过觉得设计思路不十分的好:将数据库中所有的员工都取出来,然后再筛选应该被提醒的员工。而我觉得应该直接到数据库中去做筛选,返回大量无用的数据是资源的巨大浪费(我们在甲方公司里面开发,其网络之差令人发指)。

正好,我在研究TDD(本文有时指的是测试驱动开发,有时指的是测试驱动设计,因为两者都是存在的),想想何不来一次彻底的实践,真正的、完整的来一次TDD,体味一下其中的乐趣。

由于我们的开发工具是Delphi,因此自动测试工具自然而然就要使用DUnit了。尽管有的人说TDD不一定非得用自动测试框架,我也在使用VB进行OO系统开发时,用自制的测试程序进行测试,不过觉得那样都有一种不爽的感觉。因为总需要去维护复杂的测试代码,不能全力投入到测试驱动设计中。

2       准备工作

首先介绍一下业务:

很简单,就是在一个界面上显示即将退休的人员,具体提前多少天显示是从数据库中读取的参数。

然后配置DUnit环境,网上有n多教程,然后安装了一个DUnit plug-in插件,方便开发,网上也有讲解。

Stop on Delphi Exception前的对号取消,这样就不会在出现异常时跳出了。

3       开始TDD之旅

本文是我进行TDD的实践记录,当然其间的思考要比这个多一些,不过主体部分基本都包含了,而且绝对写实。本文不是TDD的颂歌,我也提出了自己在实践中遇到的困难和疑惑。希望能给读者带来启示。

创建工程文件HR.dpr,然后使用DUnit plug-inNew Project,就自动在HR.dpr所在文件夹建了一个dunit文件夹,新建的测试工程默认名为HRTests,这是很好的规范,默认即可。然后New TestModule,建立一个测试单元。

接下来的工作就是在这两个同时开着的工程中开始工作了,一会我会切换到HRTests编写测试用例,一会我会在HR下编写产品代码,然后再回到HRTests下运行Dunit,进行测试。

3.1 领域驱动设计

   首先构建领域层,领域概念就是退休(Retired),退休人员(EmployeeRetired)了。

   先创建这两个类,不少文章说先建立测试用例,然后测试时肯定显示红条,因为被测试的类还没有建立,我觉得没建立的话连编译都过不了,怎么运行DUnit啊?

   然后就可以开始根据想象编写测试用例了。思考对象的责任和工作方式,然后切换到产品工程添加这些责任。(有点像一边画顺序图一边画类图进行责任分配) 

首先,我创建类TRetire

TRetire类分配一个责任:查找退休提醒参数:

{ 作者:零雨其蒙

创建时间:2007-5-24

Blog:blog.csdn.net/sslaowan

    www.blogjava.net/sslaowan

}

 

function TRetire.getretireAwokeParaList: TObjectList;

var paraList:TObjectList;

begin

 

   

end;

   这是一个空壳,没有实际的内容,然后切换到HRTest工程,会出现下面的对话框。


   HR工程做了任何改动,保存后,都会在HRTest中有提醒。

   可能很多人从来没见过测试用例长什么样子,下面就给出一个完整的例子。

{ 作者:零雨其蒙

创建时间:2007-5-24

Blog:blog.csdn.net/sslaowan

    www.blogjava.net/sslaowan

}

 

unit HRTestsTests;

 

interface

 

uses

  TestFrameWork,

  URetire,

  Contnrs;

 

type

   TTestRetire=class(TTestCase)

   private

      retire:TRetire;

      retirePara:TRetirePara;

   protected

        procedure SetUp; override;

        procedure TearDown; override;

   published

        procedure testGetretireAwokeParaList;

   end;

 

implementation

 

function UnitTests: ITestSuite;

var

  ATestSuite: TTestSuite;

begin

  ATestSuite := TTestSuite.Create('Retire tests');

  ATestSuite.AddTests(TTestRetire);

  Result := ATestSuite;

end;

 

{ TTestRetire }

 

procedure TTestRetire.SetUp;

begin

  inherited;

   retire:=TRetire.Create;

   retirePara:=TRetirePara.Create;

end;

 

procedure TTestRetire.TearDown;

begin

  inherited;

  retire.Free;

  retirePara.Free;

end;

 

procedure TTestRetire.testGetretireAwokeParaList;

var paraList:TObjectList;

begin

   paraList:=retire.getretireAwokeParaList;

   retirePara:=TRetirePara(paraList.Items[0]);

   check(retirePara._emp_type='管理人');

   check(retirePara._sex='');

   check(retirePara._retireage='60');

   check(retirePara._uptime='90');

 

   retirePara:=TRetirePara(paraList.Items[1]);

   check(retirePara._emp_type='管理人');

   check(retirePara._sex='');

   check(retirePara._retireage='55');

   check(retirePara._uptime='90');

 

   retirePara:=TRetirePara(paraList.Items[2]);

   check(retirePara._emp_type='工人');

   check(retirePara._sex='');

   check(retirePara._retireage='60');

   check(retirePara._uptime='90');

 

抱歉!评论已关闭.