其他语言

位置:IT落伍者 >> 其他语言 >> 浏览文章

Delphi中用TDD:一个简单的实现


发布日期:2018年05月03日
 
Delphi中用TDD:一个简单的实现

最近因工作的关系又再次搞了一些时候的Delphi开发因为Java的影响也就开始思想如何在Delphi开发中用TDD的方法这篇文章就是要谈谈TDD在Delphi中的应用我想网上已有很多的文章谈到这方面的话题我这篇也只是谈谈我自己的经验而已

那从何说起呢?用个具体的例子会更好的说明问题试想我们想开个动物繁殖中心不过我们现阶段还没有特定的动物先把这中心搞起来再说不过中心是离不开动物的我们就先定义个接口

IAnimal = Interface

procedure Mate

procedure Eat

procedure GiveBirth

End

这个接口定义了每种动物的三个基本功能Eat(吃) Mate(交配) GiveBirth(生产) 为了简单起见我们只处理母的公的不在考虑之内有了接口我们就可以定义繁殖中心

TAnimalCare= class

private

FIntf IAnimal

public

constructor Create(AnIntf IAnimal)

procedure Reproduction

end

TAnimalCare 是处理繁殖的一个类它需要依靠IAnimal才可以繁殖不过它并没有锁定任何的动物

所以在建立时需要注人一个基于IAnimal的类

有了IAnimal TAnimalCare 我们需要个测试Project来对它们进行测试DUnit是Delphi的很好的单元测试工具如你用的是Delphi DUnit已经在里面 如用的是早些的版本可在DUnit下载安装

建立好Test Project后我们可以加入下面的这个TestCase

TestTAnimalCare = class(TTestCase)

strict private

FAnimalCare TAnimalCare

public

procedure SetUp override

procedure TearDown override

published

procedure TestReproduction

end

在SetUp这里需要个基于IAnimal的类才可以至到目前我们并没有定义一个同时我们也不需要因为我们还没有特定的动物那么如何来满足这条件以便测试能进行下去呢?这里我们可以用到一种叫Mock的东西在Delphi可用PascalMock 大家可在这下载安装后我们就可以定义个TAnimalMock

TAnimalMock = class(TMock IAnimal)

public

procedure Mate

procedure Eat

procedure GiveBirth

end

procedure TestTAnimalCareSetUp

begin

FMock = TAnimalMockCreate

FAnimalCare = TAnimalCare

Create(FMock)

end

有了TAnimalMock我们已基本满足了编译的要求可以通过编译是可以开始TDD的时候了让我们先完善TestReproduction 先写些期望然后verify看有没有达到

procedure TestTAnimalCareTestReproduction

begin

// Expectations

FMockExpects(Mate

FMockExpects(Eat

FMockExpects(GiveBirth

FAnimalCareReproduction

FMockVerify(check

end

这些期望是很自然的交配(mate)营养(eat)是生产(GiveBirth)的必须条件否则是无法繁殖的我们跑一下测试失败

TestReproduction EMockVerifyException

at $BA

check

Unexpected call to GiveBirth() <—— Dont match expectations

Expected

Mate()

Eat()

GiveBirth()

Called

GiveBirth() <—— Dont match expectations

为什么?看看

procedure TAnimalCareReproduction

begin

FintfGiveBirth

end

原来我们只调用GiveBirth而没调用Mate() Eat() 不合我们的期望改成如下

procedure TAnimalCareReproduction

begin

FIntFMate

FIntFEat

FintfGiveBirth

end

再跑下测试成功!

总结

用Dependency Injection 将基于IAnimal的类注入TAnimalCare 把有关IAnimal的一些具体的实现从TAnimalCare中分离出来

用Mock来实现一个基于IAnimal的类以便测试

IAnimal TAnimalCare码如下

unit MyObjects

interface

uses

classes

type

IAnimal = Interface

procedure Mate

procedure Eat;

procedure GiveBirth;

End;

TAnimalCare= class

private

FIntf : IAnimal;

public

constructor Create(AnIntf : IAnimal);

procedure Reproduction;

end;

implementation

{ TAnimalCare }

constructor TAnimalCareCreate(AnIntf: IAnimal);

begin

inherited Create;

FintF := AnIntf;

end;

procedure TAnimalCareReproduction;

begin

FIntFMate;

FIntFEat;

FintfGiveBirth;

end;

end

测试码如下

unit TestMyObjects;

interface

uses

TestFramework classes MyObjects PascalMock;

type

TAnimalMock = class(TMock IAnimal)

public

procedure Mate;

procedure Eat;

procedure GiveBirth;

end;

TestTAnimalCare = class(TTestCase)

strict private

FMock : TAnimalMock;

FAnimalCare: TAnimalCare;

public

procedure SetUp; override;

procedure TearDown; override;

published

procedure TestReproduction;

end;

implementation

procedure TestTAnimalCareSetUp;

begin

FMock := TAnimalMockCreate;

FAnimalCare := TAnimalCareCreate(FMock);

end;

procedure TestTAnimalCareTearDown;

begin

FAnimalCareFree;

FAnimalCare := nil;

FMockFree;

FMock := nil;

end;

procedure TestTAnimalCareTestReproduction;

begin

// Expectations

FMockExpects(Mate);

FMockExpects(Eat);

FMockExpects(GiveBirth);

FAnimalCareReproduction;

FMockVerify(check);

end;

{ TAnimalMock }

procedure TAnimalMockEat;

begin

selfAddCall(Eat);

end;

procedure TAnimalMockGiveBirth;

begin

selfAddCall(GiveBirth);

end;

procedure TAnimalMockMate;

begin

selfAddCall(Mate);

end;

initialization

RegisterTest(TestTAnimalCareSuite);

end

上一篇:特效处理:Delphi中制作特效菜单

下一篇:巧妙用Delphi设计多边形窗体