Unit testing Delphi单元测试:为CUT编写一个简单的spy
我正在寻找一种方法,在Delphi下为DUnitX测试框架编写一个spy 在过去,我使用了非常丑陋的方法,使用:Unit testing Delphi单元测试:为CUT编写一个简单的spy,unit-testing,delphi,spy,dunit,dunitx,Unit Testing,Delphi,Spy,Dunit,Dunitx,我正在寻找一种方法,在Delphi下为DUnitX测试框架编写一个spy 在过去,我使用了非常丑陋的方法,使用: [TestFixture] Test = class(TObject) public [test] procedure Test1; end; TMyClass = class(TObject) protected procedure MyProcedure; virtual; end; TMyTestClass = class(TMyClass) protected
[TestFixture]
Test = class(TObject)
public
[test]
procedure Test1;
end;
TMyClass = class(TObject)
protected
procedure MyProcedure; virtual;
end;
TMyTestClass = class(TMyClass)
protected
fMyProcedureCalled : Boolean;
procedure MyProcedure; override;
end
procedure TMyTestClass.MyProcedure;
begin
fMyProcedureCalled := true;
inherited;
end;
procedure Test.Test1;
var aObj : TMyTestClass;
begin
TMyTestClass.Create;
Assert.IsTrue(aObj.fMyProcedureCalled);
end;
所有这些代码都用于检查是否调用了过程。那太冗长了
有没有办法编写一个spy来帮助我减少代码量?听起来像是模拟的用例(我在这里使用mock这个术语,因为大多数框架都将各种类型的测试加倍称为mock) 在下面的示例中,我使用的是DUnit,但它不会对DUnitX产生任何影响。我还使用了Spring4D1.2中的模拟功能(我没有检查DelphiMocks是否支持此功能)
unitmyclass;
接口
类型
TMyClass=类
私有的
fCounter:整数;
受保护的
程序我的程序;事实上的
公众的
属性计数器:整数读取fCounter;
结束;
实施
程序TMyClass.MyProcedure;
开始
公司(fCounter);
结束;
结束。
程序测试;
使用
测试框架,
Destinsight.DUnit,
春天,嘲笑,
“MyClass.pas”中的MyClass;
类型
TMyClass=class(MyClass.TMyClass)
公众的
//只是为了便于测试
程序我的程序;推翻
结束;
TMyTest=类(TTestCase)
出版
程序测试1;
结束;
程序TMyClass.MyProcedure;
开始
继承;
结束;
程序TMyTest.Test1;
变量
//模拟在第一次使用时自动初始化
//默认为TMockBehavior.Dynamic,这意味着它允许所有调用发生
m:模拟;
o:TMyClass;
开始
//将其设置为true以实际调用“real”方法
m、 CallBase:=True;
//用o做点什么
o:=m;
o、 我的程序;
//检查预期呼叫是否确实发生
m、 收到(次。一次)。我的程序;
//证明它确实调用了“真实”方法
CheckEquals(1,o.计数器);
结束;
开始
注册测试(TMyTest.Suite);
RunRegisteredTests();
结束。
请记住,这只适用于虚拟方法。如果需要测试基类中不受
$RTTI
指令影响的方法,可以使用一些小技巧,在public
部分的子类中将其重新定义为覆盖;摘要代码>这将导致生成RTTI。谢谢你们的回答。我不知道Spring4d有这种模拟功能。非常方便!
unit MyClass;
interface
type
TMyClass = class
private
fCounter: Integer;
protected
procedure MyProcedure; virtual;
public
property Counter: Integer read fCounter;
end;
implementation
procedure TMyClass.MyProcedure;
begin
Inc(fCounter);
end;
end.
program Tests;
uses
TestFramework,
TestInsight.DUnit,
Spring.Mocking,
MyClass in 'MyClass.pas';
type
TMyClass = class(MyClass.TMyClass)
public
// just to make it accessible for the test
procedure MyProcedure; override;
end;
TMyTest = class(TTestCase)
published
procedure Test1;
end;
procedure TMyClass.MyProcedure;
begin
inherited;
end;
procedure TMyTest.Test1;
var
// the mock is getting auto initialized on its first use
// and defaults to TMockBehavior.Dynamic which means it lets all calls happen
m: Mock<TMyClass>;
o: TMyClass;
begin
// set this to true to actually call the "real" method
m.CallBase := True;
// do something with o
o := m;
o.MyProcedure;
// check if the expected call actually did happen
m.Received(Times.Once).MyProcedure;
// to prove that it actually did call the "real" method
CheckEquals(1, o.Counter);
end;
begin
RegisterTest(TMyTest.Suite);
RunRegisteredTests();
end.