-
Notifications
You must be signed in to change notification settings - Fork 113
Quick Start Guide
##Delphi-Mocks
Delphi-Mocks is simple mocking framework for Delphi. It's intended to be used in conjunction with unit testing. The api is fluent where possible, and strongly typed where possible.
###RTTI on interfaces
Delph-Mocks currently only supports mocking interfaces, and is only supported in Delphi XE2. An interface must have Runtime Type Information (RTTI), to enable RTTI on an interface, add the {$M+} compiler directive before it.
{$M+}
IFoo = interface
function Bar(param : integer) : string;overload;
function Bar(param : integer; param2 : string) : string;overload;
procedure TestMe;
end;
###Creating the Mock.
We make extensive use of Generics in the framework. To create the mock, we use the TInterfaceMock<T>.Create class function where T is the interface we want to mock. Since delphi generics
procedure Test;
var
mock : TInterfaceMock<IFoo>; //our mock object
begin
//Create our mock
mock := TInterfaceMock<IFoo>.Create;
...
end;
###Setting up the Mock behavior.
The behavior of the Mock is controlled by the TInterfaceMock<T>.Setup method. This method returns an ISetup<T> reference, where we can control what the return values of methods will be.
//We use the Setup to configure our expected behaviour rules and to verify
//that those expectations were met.
ISetup<T> = interface
//Set Expectations for methods
function Expect : IExpect<T>;
//set the return value for a method when called with the parameters specified on the When
function WillReturn(const value : TValue) : IWhen<T>;
//Will exedute the func when called with the specified parameters
function WillExecute(const func : TExecuteFunc) : IWhen<T>;overload;
//will always execute the func no matter what parameters are specified.
procedure WillExecute(const AMethodName : string; const func : TExecuteFunc);overload;
//set the default return value for a method when it is called with parameter values we
//haven't specified
procedure WillReturnDefault(const AMethodName : string; const value : TValue);
//set the Exception class that will be raised when the method is called with the parmeters specified
function WillRaise(const exceptionClass : ExceptClass; const message : string = '') : IWhen<T>;overload;
//This method will always raise an exception.. this behavior will trump any other defined behaviors
procedure WillRaise(const AMethodName : string; const exceptionClass : ExceptClass; const message : string = '');overload;
end;
So lets setup the behavior of our IFoo Mock
//setup a default return value for method Bar
mock.Setup.WillReturnDefault('Bar','hello world');
//setup explicit return values when parameters are matched
mock.Setup.WillReturn('blah blah').When.Bar(1);
mock.Setup.WillReturn('goodbye world').When.Bar(2,'sdfsd'); //call an overloaded method
//calling Bar with a value of 20 will invoke the supplied anonymous function
mock.Setup.WillExecute(
function (const args : TArray<TValue>; const ReturnType : TRttiType) : TValue
begin
//Note - args[0] is the Self interface reference for the anon method, our first arg is [1]
result := 'The result is ' + IntToStr(args[1].AsOrdinal);
end
).When.Bar(200);
mock.Setup.WillRaise(EDontCallMeIllCallYou,'You called me when I told you not to!').When.TestMe;
###Setting our expectations of how the Mock will be used.
Setting expectations on a Mock allows you to verify that the interactions with your mock object were as you expected. Expectations are set through the Expect method of the Setup reference. Again we use a fluent style interface to define our expectations.
mock.Setup.Expect.AtLeastOnce.When.Bar(1);
mock.Setup.Expect.AtLeastOnce.When.Bar(99);
mock.Setup.Expect.Between(2,4).When.Bar(23);
mock.Setup.Expect.Exactly('Bar',5);
mock.Setup.Expect.Never.When.TestMe;
Some checking is done when defining Expectations for overlapping or conflicting expectations, however the checking is very basic. Detected conflicting expectations will raise an exception.
###Using the Mock.
The TInterfaceMock<T> type has an Instance function which returns a reference to our interface T. So to call a method on our mock object, we can call it like this :
mock.Instance.Bar(1);
TInterfaceMock<T> also implements an Implicit operator overload that makes it castable to T
class operator Implicit(const Value: TInterfaceMock<T>): T;
So if you have a procedure or method that takes a parameter of interface type T, you can just pass it your mock :
procedure Test;
var
mock : TInterfaceMock<IFoo>; //our mock object
procedure TestImplicit(value : IFoo);
begin
WriteLn('Calling Bar(1234567) : ' + value.Bar(1234567));
end;
begin
TestImplicit(mock); //uses the Implicit Operator overload
end;