2013-08-16 21 views
5

Tôi vừa mới bắt đầu sử dụng Delphi-Mocks với các bài kiểm tra dunit của tôi nhưng nó có ít hoặc không có tài liệu.Delphi Mocks - Có thể sử dụng sắp xếp ‘VAR’ hoặc ‘OUT’ trong một chức năng được mô phỏng bằng ‘WillReturn’ không?

Vấn đề là:

Tôi cố gắng để viết một bài kiểm tra 'Test_LogonUser_CheckPwd_GOOD_PASSWORD'

Nhưng tôi không chắc chắn làm thế nào để thử ra chức năng Fusers.CheckPwd (TEST_USERID, TEST_PASSWORD, ERROR_CODE);

Thông thường tôi sẽ sử dụng: Fusers.Setup.WillReturn (True) .When.CheckPwd (TEST_USERID, TEST_PASSWORD, ERROR_CODE);

Nhưng ‘ERROR_CODE’ là một giá trị OUT và đưa ra một lỗi biên dịch

CÂU HỎI:

  1. Có cách nào để làm cho công việc ‘WillReturn’ với OUT hoặc VAR thông số?
  2. Có cách nào khác để giả lập ‘CheckPwd’ để nó xem xét thông số OUT hoặc VAR không?

Đây là mã của tôi:

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

Trả lời

4

AFAIK đây là giới hạn của việc triển khai lớp tiêu chuẩn TVirtualInterface, mà trên đó Delphi mocks dựa vào. Đây là một trong những điểm yếu/hạn chế của "RTTI mới".

Giải pháp duy nhất có thể là sử dụng thư viện khoanh vùng/chế nhạo không sử dụng lớp TVirtualInterface này.

Thư viện duy nhất tôi biết có nhà máy "lớp ảo" riêng của mình, là our Open Source mORMot framework (đối với Delphi 6 lên đến XE4, trong Win32 và Win64). Nó hỗ trợ các tham số giá trị varout. Để thử nghiệm bất kỳ giá trị tham số nào, bạn có thể sử dụng phương thức ExpectsTrace() - nhờ vào số lớn "Call Tracing" feature of mORMot.

2

Thư viện bạn đang sử dụng cung cấp cho không xem xét các thông số thông qua tham khảo. Nó xử lý tất cả các tham số như các giá trị đầu vào được kết hợp trên một cuộc gọi đến mô hình. Hơn nữa, nó không có cách nào để gán các giá trị mới cho các tham số như vậy khi hàm được mô phỏng được gọi.

Một cách khác là bạn thay đổi giao diện cho hàm của bạn để làm cho nó có thể kiểm chứng. Bạn có thể ném một ngoại lệ về thất bại. Tuy nhiên, các ngoại lệ không thực sự phù hợp với chức năng này vì không nhập đúng tên người dùng và mật khẩu không phải là một sự kiện đặc biệt. Thay vào đó, hãy xem xét trả lại mã lỗi. Đặt một mã (thường là 0) để cho biết thành công.

+2

Thay đổi giao diện của bạn vì một hạn chế của bên thứ ba (mà thực tế là giới hạn RTA RTL của Delphi)? Có rất nhiều trường hợp tham số 'var' và' out' là giải pháp tốt nhất cho định nghĩa phương thức. Hoặc bạn có thể phải sử dụng một lớp hoặc bản ghi là loại kết quả "tupple" ... Tôi không tin rằng nó là "pascalish" hơn. –

2

New delphi-giả có thể làm điều này bằng tài liệu tham khảo-to-Hàm-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); 

(tôi sử dụng Delphi XE7 và DUnitX)

+0

Cảm ơn bạn rất nhiều! Câu trả lời này vừa cứu tôi !! –

+0

Thú vị sẽ cần thêm ngữ cảnh về cách sử dụng –

Các vấn đề liên quan