Delphi Mocks–;是否可以使用‘;VAR’;或‘;OUT’;用‘;将返回&x2019;?

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

我刚刚开始使用dunit测试,但它几乎没有文档

问题是:

我正在尝试编写一个测试'test\u LogonUser\u CheckPwd\u GOOD\u PASSWORD'

但我不知道如何模拟这个函数 fuser.CheckPwd(测试用户ID、测试密码、错误代码)

通常我会使用: Fusers.Setup.WillReturn(True).When.CheckPwd(测试用户ID、测试密码、错误代码)

但是'ERROR_CODE'是一个OUT值,并给出一个编译错误

问题:

/////  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;
  • 有没有办法让“WillReturn”在没有OUT或VAR参数的情况下工作
  • 是否有其他方法模拟“CheckPwd”,以便它查看out或VAR参数
  • 这是我的代码:

    /////  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