Delphi Mocks–;是否可以使用‘;VAR’;或‘;OUT’;用‘;将返回&x2019;?
我刚刚开始使用dunit测试,但它几乎没有文档 问题是: 我正在尝试编写一个测试'test\u LogonUser\u CheckPwd\u GOOD\u PASSWORD' 但我不知道如何模拟这个函数 fuser.CheckPwd(测试用户ID、测试密码、错误代码)强> 通常我会使用: Fusers.Setup.WillReturn(True).When.CheckPwd(测试用户ID、测试密码、错误代码)强> 但是'ERROR_CODE'是一个OUT值,并给出一个编译错误 问题:Delphi Mocks–;是否可以使用‘;VAR’;或‘;OUT’;用‘;将返回&x2019;?,delphi,delphi-xe2,dunit,delphi-mocks,Delphi,Delphi Xe2,Dunit,Delphi Mocks,我刚刚开始使用dunit测试,但它几乎没有文档 问题是: 我正在尝试编写一个测试'test\u LogonUser\u CheckPwd\u GOOD\u PASSWORD' 但我不知道如何模拟这个函数 fuser.CheckPwd(测试用户ID、测试密码、错误代码) 通常我会使用: Fusers.Setup.WillReturn(True).When.CheckPwd(测试用户ID、测试密码、错误代码) 但是'ERROR_CODE'是一个OUT值,并给出一个编译错误 问题: ///// TD
///// TDlUsers
interface
type
{$M+}
IDlUsers = Interface(IInterface)
['{3611B437-888C-4919-B304-238A80DAD476}']
function VerifyPassword(UserId: integer; Pwd: string): Boolean;
function CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer) : Boolean;
end;
function Dl_Users : IDlUsers;
{$M-}
implementation
type
TDlUsers = class(TDbIControl,IDlUsers)
public
function VerifyPassword(UserId: integer; Pwd: string): Boolean;
function CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean;
end;
function Dl_Users : IDlUsers;
begin
result := TDlUsers.create;
end;
//// TUserCtrl
interface
uses DlUsers;
type
TUserCtrl = class
private
FUsers : IDlUsers;
public
function LogonUser_CheckPwd(UserID: Integer; Pwd: String): Boolean;
function LogonUser_VerifyPassword(UserID: Integer; Pwd: String): Boolean;
constructor Create; overload;
constructor Create(FUsers : IDlUsers); overload; { used for Dependency injection }
end;
implementation
constructor TUserCtrl.Create;
begin
Create(Dl_Users);
end;
constructor TUserCtrl.Create(FUsers : IDlUsers);
begin
Self.FUsers := FUsers;
end;
function TUserCtrl.LogonUser_VerifyPassword(UserID: Integer; Pwd: String): Boolean;
begin
result := FUsers.VerifyPassword(UserId,Pwd);
end
function TUserCtrl.LogonUser_CheckPwd(UserID: Integer; Pwd: String): Boolean;
var ErrorCode : Integer;
begin
result := FUsers.CheckPwd(UserID,Pwd,ErrorCode);
// do what needs to be done with ErrorCode
end;
///// Unit tests
procedure TestTDlUsers.SetUp;
begin
inherited;
FUsers := TMock<IDlUsers>.Create;
FUserCtrl := TUserCtrl.Create(FUsers);
end;
procedure TestTDlUsers.Test_LogonUser_VerifyPassword_GOOD_PASSWORD;
var Answer : Boolean;
begin
FUsers.Setup.WillReturnDefault('VerifyPassword',False);
FUsers.Setup.WillReturn(True).When.VerifyPassword(TEST_USERID,TEST_PASSWORD);
Answer := FUserCtrl.LogonUser_VerifyPassword(TEST_USERID,TEST_PASSWORD,ErrorCode,ErrorMsg);
CheckEquals(True,Answer);
end;
procedure TestTDlUsers.Test_LogonUser_CheckPwd_GOOD_PASSWORD;
var Answer : Boolean;
begin
FUsers.Setup.WillReturnDefault('CheckPwd',False);
// MAJOR Problem with line CheckPwd has an Out pramater
FUsers.Setup.WillReturn(True).When.CheckPwd(TEST_USERID,TEST_PASSWORD, ERROR_CODE);
Answer := FUserCtrl.LogonUser_CheckPwd(TEST_USERID,TEST_PASSWORD,ErrorCode,ErrorMsg);
CheckEquals(True,Answer);
end;
///// TDlUsers
interface
type
{$M+}
IDlUsers = Interface(IInterface)
['{3611B437-888C-4919-B304-238A80DAD476}']
function VerifyPassword(UserId: integer; Pwd: string): Boolean;
function CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer) : Boolean;
end;
function Dl_Users : IDlUsers;
{$M-}
implementation
type
TDlUsers = class(TDbIControl,IDlUsers)
public
function VerifyPassword(UserId: integer; Pwd: string): Boolean;
function CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean;
end;
function Dl_Users : IDlUsers;
begin
result := TDlUsers.create;
end;
//// TUserCtrl
interface
uses DlUsers;
type
TUserCtrl = class
private
FUsers : IDlUsers;
public
function LogonUser_CheckPwd(UserID: Integer; Pwd: String): Boolean;
function LogonUser_VerifyPassword(UserID: Integer; Pwd: String): Boolean;
constructor Create; overload;
constructor Create(FUsers : IDlUsers); overload; { used for Dependency injection }
end;
implementation
constructor TUserCtrl.Create;
begin
Create(Dl_Users);
end;
constructor TUserCtrl.Create(FUsers : IDlUsers);
begin
Self.FUsers := FUsers;
end;
function TUserCtrl.LogonUser_VerifyPassword(UserID: Integer; Pwd: String): Boolean;
begin
result := FUsers.VerifyPassword(UserId,Pwd);
end
function TUserCtrl.LogonUser_CheckPwd(UserID: Integer; Pwd: String): Boolean;
var ErrorCode : Integer;
begin
result := FUsers.CheckPwd(UserID,Pwd,ErrorCode);
// do what needs to be done with ErrorCode
end;
///// Unit tests
procedure TestTDlUsers.SetUp;
begin
inherited;
FUsers := TMock<IDlUsers>.Create;
FUserCtrl := TUserCtrl.Create(FUsers);
end;
procedure TestTDlUsers.Test_LogonUser_VerifyPassword_GOOD_PASSWORD;
var Answer : Boolean;
begin
FUsers.Setup.WillReturnDefault('VerifyPassword',False);
FUsers.Setup.WillReturn(True).When.VerifyPassword(TEST_USERID,TEST_PASSWORD);
Answer := FUserCtrl.LogonUser_VerifyPassword(TEST_USERID,TEST_PASSWORD,ErrorCode,ErrorMsg);
CheckEquals(True,Answer);
end;
procedure TestTDlUsers.Test_LogonUser_CheckPwd_GOOD_PASSWORD;
var Answer : Boolean;
begin
FUsers.Setup.WillReturnDefault('CheckPwd',False);
// MAJOR Problem with line CheckPwd has an Out pramater
FUsers.Setup.WillReturn(True).When.CheckPwd(TEST_USERID,TEST_PASSWORD, ERROR_CODE);
Answer := FUserCtrl.LogonUser_CheckPwd(TEST_USERID,TEST_PASSWORD,ErrorCode,ErrorMsg);
CheckEquals(True,Answer);
end;
///TDlUsers
接口
类型
{$M+}
IDlUsers=接口(I接口)
[{3611B437-888C-4919-B304-238A80DAD476}]
函数VerifyPassword(UserId:integer;Pwd:string):布尔;
函数CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer):布尔;
结束;
功能Dl_用户:IDlUsers;
{$M-}
实施
类型
TDlUsers=类(TDbIControl,IDlUsers)
公众的
函数VerifyPassword(UserId:integer;Pwd:string):布尔;
函数CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):布尔值;
结束;
功能Dl_用户:IDlUsers;
开始
结果:=TDlUsers.create;
结束;
////图塞克特尔
接口
使用数据链路用户;
类型
TUserCtrl=类
私有的
融合器:空闲用户;
公众的
函数LogonUser_CheckPwd(UserID:Integer;Pwd:String):布尔;
函数LogonUser_VerifyPassword(UserID:Integer;Pwd:String):布尔;
构造函数创建;超载;
构造函数创建(融合器:IDlUsers);超载;{用于依赖项注入}
结束;
实施
构造函数TUserCtrl.Create;
开始
创建(Dl_用户);
结束;
构造函数TUserCtrl.Create(fuser:IDlUsers);
开始
Self.fuser:=定影器;
结束;
函数TUserCtrl.LogonUser\u VerifyPassword(UserID:Integer;Pwd:String):布尔;
开始
结果:=FUsers.VerifyPassword(UserId,Pwd);
结束
函数TUserCtrl.LogonUser_CheckPwd(UserID:Integer;Pwd:String):布尔;
var错误代码:整数;
开始
结果:=FUsers.CheckPwd(UserID、Pwd、ErrorCode);
//使用ErrorCode执行需要执行的操作
结束;
/////单元测试
程序TestTDlUsers.SetUp;
开始
继承;
融合器:=TMock.Create;
FUserCtrl:=TUserCtrl.Create(fuser);
结束;
程序TestTDlUsers.Test_LogonUser_VerifyPassword_GOOD_PASSWORD;
答案:布尔;
开始
FUsers.Setup.WillReturnDefault('VerifyPassword',False);
FUsers.Setup.WillReturn(True).When.VerifyPassword(TEST\u USERID,TEST\u PASSWORD);
回答:=FUserCtrl.LogonUser\u验证密码(TEST\u用户ID、TEST\u密码、ErrorCode、ErrorMsg);
CheckEquals(正确,答案);
结束;
程序TestTDlUsers.Test_LogonUser_CheckPwd_GOOD_PASSWORD;
答案:布尔;
开始
FUsers.Setup.WillReturnDefault('CheckPwd',False);
//线路检查PWD的主要问题是有一个错误
FUsers.Setup.WillReturn(True).When.CheckPwd(测试用户ID、测试密码、错误代码);
回答:=FUserCtrl.LogonUser\u CheckPwd(测试用户ID、测试密码、错误代码、错误消息);
CheckEquals(正确,答案);
结束;
您使用的库不考虑通过引用传递的参数。它将所有参数视为输入值,在调用mock时进行匹配。此外,在调用模拟函数时,它无法为这些参数指定新值
另一种方法是更改函数的接口,使其可测试。失败时可以抛出异常。但是,由于未能输入正确的用户名和密码不是异常事件,因此异常并不真正适用于此函数。相反,考虑返回错误代码。保留一个代码(通常为零)表示成功。AFAIK这是Delphi mocks所依赖的
TVirtualInterface
标准类实现的一个限制。这是“新RTTI”的弱点/局限之一
唯一可能的解决方案是使用存根/模拟库,该库不使用此TVirtualInterface
类
我所知道的唯一一个拥有自己的“虚拟类”工厂的库是(对于Delphi6到XE4,在Win32和Win64下)。它支持
var
和out
值参数。为了测试任何out参数值,您可以使用ExpectsTrace()
方法-这要归功于强大的功能。新的delphi mock可以通过引用函数WillExecute来完成:
FUsers.Setup.WillExecute('CheckPwd',
// function CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg: String) : Boolean;
function (const args : TArray<TValue>; const ReturnType : TRttiType) : TValue
var
aErrorCode: Integer;
aErrorMsg: String;
aResult: Boolean
begin
// check against 5, as arg[0] is tkInterface and the method parameters start with arg[1]
Assert.AreEqual(5, Length(args), 'wrong number of arguments passed to IDlUsers.CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean');
Assert.IsTrue(args[1].IsType<integer>, 'wrong argument 1 type passed to IDlUsers.CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean');
Assert.IsTrue(args[2].IsType<string>, 'wrong argument 2 type passed to IDlUsers.CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean');
Assert.IsTrue(args[3].IsType<Integer>, 'wrong argument 3 type passed to IDlUsers.CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean');
Assert.IsTrue(args[4].IsType<string>, 'wrong argument 4 type passed to IDlUsers.CheckPwd(UserId: integer; Pwd: string; out ErrorCode: Integer; out ErrorMsg:String) : Boolean');
// ...
arg[3] := TValue.From<Integer>(aErrorCode);
arg[4] := TValue.From<string>(aErrorMsg);
Result := TValue.From<Boolean>(aResult);
end);
FUsers.Setup.WillExecute('CheckPwd',
//函数CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):布尔值;
函数(常量参数:TArray;常量返回类型:TRttiType):TValue
变量
aErrorCode:整数;
aErrorMsg:字符串;
结果:布尔值
开始
//对照5进行检查,因为arg[0]是tkInterface,并且方法参数以arg[1]开头
AreEqual(5,长度(args),'传递给IDlUsers的参数数目错误。CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):Boolean');
Assert.IsTrue(args[1].IsType,'传递给IDlUsers的参数1类型错误。CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):Boolean');
Assert.IsTrue(args[2].IsType,'传递给IDlUsers的参数2类型错误。CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):Boolean');
Assert.IsTrue(args[3].IsType,'传递给IDlUsers的参数3类型错误。CheckPwd(UserId:integer;Pwd:string;out ErrorCode:integer;out ErrorMsg:string):Boolean');
Assert.IsTrue(args[4].IsType