Delphi. Mock FrameWork

Открыл для себя Mock FrameWork. Работает, начиная с XE2. Основное назначение – эмуляция тестовых случаев в юнит тестах, “а что будет с методом, если переменная будет такая, а другая?”

GitHub

Далее, я сделаю некоторый вольный перевод статьи с GitHub. Mock FrameWork поддерживает интерфейсы и классы. Интерфейс должен иметь RTTI информацию, на борту, для этого необходимо включить директиву {$M+}

{$M+}
IFoo = interface
 function Bar(param : integer) : string;overload;
 function Bar(param : integer; param2 : string) : string;overload;
 procedure TestMe;
end;

Авторы фрэймворка широко используют Generics, например так

procedure Test;
var
  mock : TMock<IFoo>; //our mock object
begin
  //Create our mock
  mock := TMock<IFoo>.Create;
 ...
end;

Настройка ожидаемого поведения задается следующим образом

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

Настроим ожидаемое поведение в нашем примере

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

Настройка наших ожиданий

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;

Если результат не совпадет с нашими ожиданиями, выпадет Exception

У TMock<T> есть ссылка на объект, то есть мы можем сделать так

mock.Instance.Bar(1); 

TMock<T>  также поддерживает оператор Implicit, который позволяет его приводить к типу T

class operator Implicit(const Value: TMock<T>): T;

Далее приводится такой пример теста

procedure Test;
var
  mock : TMock<IFoo>; //our mock object

  procedure TestImplicit(value : IFoo);
  begin
    WriteLn('Calling Bar(1234567) : ' + value.Bar(1234567));
  end;
begin
  //Create our mock
  mock := TMock<IFoo>.Create;
  TestImplicit(mock); //uses the Implicit Operator overload
end;

Проверка наших ожиданий

mock.Verify("My Expectations were not met!!"); //The message is optional.

Если все ожидания совпали, фрэймворк не заругается, иначе получим такую ошибку

EMockVerificationException: My Expectations were not met!!
  Method : Bar
    Expectation [ At Least Once When( 99 ) ] was not met.
    Expectation [ Between 2 and 4 Times When( 23 ) ] was not met.
  Method : TestMe
    Expectation [ Never When(  ) ] was not met.
This entry was posted in Без рубрики. Bookmark the permalink.