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

delphi, delphi-mocks, delphi-xe2, dunit

Solution

AFAIK this is a limitation of the `TVirtualInterface` standard class implementation, on which Delphi mocks relies. This is one of the weaknesses/limitations of the "new RTTI".

The only possible solution is to use a stubbing/mocking library which does not use this `TVirtualInterface` class.

The only library I know which has its own "virtual class" factory, is our Open Source mORMot framework (for Delphi 6 up to XE4, under Win32 and Win64). It supports `var` and `out` value parameters. For testing any out parameter value, you can use the `ExpectsTrace()` method - thanks to the great "Call Tracing" feature of mORMot.

Problem

I have just started to use Delphi-Mocks with my dunit tests but it has little or no documentation. The Problem is: I am trying to write a test ‘Test_LogonUser_CheckPwd_GOOD_PASSWORD’ But I am not sure how to mock out the function Fusers.CheckPwd(TEST_USERID,TEST_PASSWORD, ERROR_CODE); Normally I would use: Fusers.Setup.WillReturn(True).When.CheckPwd(TEST_USERID,TEST_PASSWORD, ERROR_CODE); But ‘ERROR_CODE’ is an OUT value and gives a compile error QUESTIONS: - Is there a way to make ‘WillReturn’ work with OUT or VAR parameters ? - Is there a different way to mock out ‘CheckPwd’ so that it looks at OUT or VAR parameters ? Here is my code: ``` ///// 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; ```

Original source