簡體   English   中英

德爾福模擬 - 是否可以在使用'WillReturn'模擬的函數中使用'VAR'或'OUT'排列?

[英]Delphi Mocks – Is it possible to use ‘VAR’ or ‘OUT’ arrangements in a function that is been mocked with a ‘WillReturn’?

我剛開始使用Delphi- Mocks和我的dunit測試,但它幾乎沒有文檔。

問題是:

我正在嘗試編寫測試'Test_LogonUser_CheckPwd_GOOD_PASSWORD'

但我不知道如何模擬函數Fusers.CheckPwd(TEST_USERID,TEST_PASSWORD,ERROR_CODE);

通常我會使用: Fusers.Setup.WillReturn(True).When.CheckPwd(TEST_USERID,TEST_PASSWORD,ERROR_CODE);

但是'ERROR_CODE'是一個OUT值並且給出了編譯錯誤

問題:

  1. 有沒有辦法讓'WillReturn'與OUT或VAR參數一起工作?
  2. 有沒有不同的方法來模擬'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;

AFAIK這是對Delphi TVirtualInterface依賴的TVirtualInterface標准類實現的限制。 這是“新RTTI”的弱點/局限之一。

唯一可行的解​​決方案是使用不使用此TVirtualInterface類的存根/ TVirtualInterface庫。

我所知道的唯一擁有自己的“虛擬類”工廠的庫是我們的開源mORMot框架 (適用於Delphi 6到XE4,在Win32和Win64下)。 它支持varout值參數。 為了測試出任何的參數值,你可以使用ExpectsTrace()方法-感謝偉大的“呼叫追蹤” mORMot的功能

新的delphi-mock可以使用reference-to-function-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);

(我使用Delphi XE7和DUnitX)

您正在使用的庫不考慮通過引用傳遞的參數。 它將所有參數視為在調用mock時匹配的輸入值。 此外,當調用模擬函數時,它無法為這些參數賦值。

另一種方法是更改​​函數的界面以使其可測試。 您可以在失敗時拋出異常。 但是,異常並不適合此功能,因為輸入正確的用戶名和密碼不是特殊事件。 相反,請考慮返回錯誤代碼。 保留一個代碼(通常為零)以表示成功。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM