Code Monkey home page Code Monkey logo

delphi-mocks's Introduction

Delphi Mocks

Delphi Mocks is a simple mocking framework for Delphi XE2 or later. It makes use of RTTI features that are only available in Delphi XE2. See the example at the bottom of the space for a complete explanation.

Parameter matching

To match expectations or behavior there is extended parameter matching.

    function IsAny<T>() : T ;
    function Matches<T>(const predicate: TPredicate<T>) : T;
    function IsNotNil<T> : T; overload;
    function IsNotNil<T>(const comparer: IEqualityComparer<T>) : T; overload;
    function IsEqualTo<T>(const value : T) : T; overload;
    function IsEqualTo<T>(const value : T; const comparer: IEqualityComparer<T>) : T; overload;
    function IsInRange<T>(const fromValue : T; const toValue : T) : T;
    function IsIn<T>(const values : TArray<T>) : T; overload;
    function IsIn<T>(const values : TArray<T>; const comparer: IEqualityComparer<T>) : T; overload;
    function IsIn<T>(const values : IEnumerable<T>) : T; overload;
    function IsIn<T>(const values : IEnumerable<T>; const comparer: IEqualityComparer<T>) : T; overload;
    function IsNotIn<T>(const values : TArray<T>) : T; overload;
    function IsNotIn<T>(const values : TArray<T>; const comparer: IEqualityComparer<T>) : T; overload;
    function IsNotIn<T>(const values : IEnumerable<T>) : T; overload;
    function IsNotIn<T>(const values : IEnumerable<T>; const comparer: IEqualityComparer<T>) : T; overload;
    function IsRegex(const regex : string; const options : TRegExOptions = []) : string;
    function AreSamePropertiesThat<T>(const Value: T): T;
    function AreSameFieldsThat<T>(const Value: T): T;
    function AreSameFieldsAndPropertiedThat<T>(const Value: T): T;

Usage is easy:

  mock.Setup.Expect.Once.When.SimpleMethod(It0.IsAny<Integer>, It1.IsAny<String>);
  mock.Setup.WillReturn(3).When.SimpleFunction(It0.IsEqualTo<String>('hello'));

Class matching

Some more attention should be payed for matching classes. Usage of .IsAny<TMyClass> will not work as might be expected, because nil (which is the default return value of IsAny<T>) is always a good match. Therefore the following setup will fail on the second line, because the framework will think that there is already behavior defined (in the first line).

  mock.Setup.Expect.Never.When.ExtendedMethod(It0.IsAny<TMyClass>);
  mock.Setup.Expect.Never.When.ExtendedMethod(It0.IsAny<TMyOtherClass>);

This can easily be solved by using .IsNotNil<TMyClass>:

  mock.Setup.Expect.Never.When.ExtendedMethod(It0.IsNotNil<TMyClass>);
  mock.Setup.Expect.Never.When.ExtendedMethod(It0.IsNotNil<TMyOtherClass>);

Example

unit Delphi.Mocks.Examples.Interfaces;

interface

uses
  SysUtils,
  DUnitX.TestFramework,
  Delphi.Mocks;

type
  {$M+}
  TSimpleInterface = Interface
    ['{4131D033-2D80-42B8-AAA1-3C2DF0AC3BBD}']
    procedure SimpleMethod;
  end;

  TSystemUnderTestInf = Interface
    ['{5E21CA8E-A4BB-4512-BCD4-22D7F10C5A0B}']
    procedure CallsSimpleInterfaceMethod;
  end;
  {$M-}

  TSystemUnderTest = class(TInterfacedObject, TSystemUnderTestInf)
  private
    FInternalInf : TSimpleInterface;
  public
    constructor Create(const ARequiredInf: TSimpleInterface);
    procedure CallsSimpleInterfaceMethod;
  end;

  TMockObjectTests = class
  published
    procedure Simple_Interface_Mock;
  end;

implementation

uses
  System.Rtti;

{ TMockObjectTests }

procedure TMockObjectTests.Simple_Interface_Mock;
var
  mock : TMock<TSimpleInterface>;
  sutObject : TSystemUnderTestInf;
begin
  //SETUP: Create a mock of the interface that is required by our system under test object.
  mock := TMock<TSimpleInterface>.Create;

  //SETUP: Add a check that SimpleMethod is called atleast once.
  mock.Setup.Expect.AtLeastOnce.When.SimpleMethod;

  //SETUP: Create the system under test object passing an instance of the mock interface it requires.
  sutObject := TSystemUnderTest.Create(mock.Instance);

  //TEST: Call CallsSimpleInterfaceMethod on the system under test.
  sutObject.CallsSimpleInterfaceMethod;

  //VERIFY: That our passed in interface was called at least once when CallsSimpleInterfaceMethod was called.
  mock.Verify('CallsSimpleInterfaceMethod should call SimpleMethod');
end;

{ TSystemUnderTest }

procedure TSystemUnderTest.CallsSimpleInterfaceMethod;
begin
  FInternalInf.SimpleMethod;
end;

constructor TSystemUnderTest.Create(const ARequiredInf: TSimpleInterface);
begin
  FInternalInf := ARequiredInf;
end;

end.

delphi-mocks's People

Contributors

andreasddi avatar asiwon avatar coppensbart avatar fabioxgn avatar fabriciocolombo avatar felisatinform avatar henriquewerlang avatar hubalazs avatar igorts2004 avatar jensweigele avatar kennethcochran avatar laurensvanrun avatar martinsedgewick avatar nickhodges avatar rlove avatar rpottsoh avatar shadow-cs avatar staticcat avatar teloah avatar vincentparrett avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delphi-mocks's Issues

TMock fails with some methods that do not pass the Self reference

I'm not sure why, but I have an abstract base class that when I mock it out the Self parameter is not passed in the method call...

This causes TBehaviour.Match to fail because it filters out the first parameter, and if there is only one parameter it ignores it and effectively assumes the function has no parameters at all.

For example, my base class is:

  TSettings = class
    public
      function ReadInteger(const AName: String): integer; virtual;
      function ReadString(const AName: string): string; virtual; abstract;
      function ReadBool(const AName: string): Boolean; virtual;
      function ReadFloat(const AName: string): double; virtual;
      function ReadEnum(const AName: string): integer; virtual;
      function WriteInteger(const AName: string; const AValue: integer): TSettings; virtual;
      function WriteString(const AName, AValue: string): TSettings; virtual; abstract;
      function WriteBool(const AName: string; const AValue: boolean): TSettings; virtual;
      function WriteFloat(const AName: string; const AValue: double): TSettings; virtual;
      function WriteEnum(const AName: string; const AValue: integer): TSettings; virtual;

      procedure Changed; virtual;

      procedure GetNames(AString: TStrings); virtual;

      procedure DeleteSection; virtual;
      procedure DeleteKey(AKey: string); virtual;

    end;

When I mock it out, like this:

    LMockSettings := TMock<TSettings>.Create;
    try
      LMockSettings.Setup.WillReturn('..\datadefinitions\').When.ReadString('DefinitionPath');
      LMockSettings.Setup.WillReturn('test\').When.ReadString('Path');


      // ... testing code

    finally
      LMockSettings.Free;
    end;

I get an exception on the second WillReturn line:

  Project TestPersistance.exe raised exception class EMockSetupException with message
  'WillReturn.When already defined with these parameters for method ReadString'.

In Delphi.Mocks.Behaviour, the Match method assumes that the first parameter of the of any call will be the "self"reference (as you would expect):

  function TBehavior.Match(const Args: TArray<TValue>): Boolean;

    function MatchArgs : boolean;
    var
      i : integer;
    begin
      result := False;
      if Length(Args) <> (Length(FArgs) + 1) then
        exit;
      //start at 1 because we don't care about matching the first arg (self pointer)
      for i := 1 to Length(args) -1 do
      begin
        if not FArgs[i-1].Equals(args[i]) then
          exit;
      end;
      result := True;
    end;

  begin
    result := False;
    case FBehaviorType of
      WillReturn      : result := MatchArgs;
      ReturnDefault   : result := True;
      WillRaise       :
      begin
        result := MatchArgs;
        if FExceptClass <> nil then
          raise FExceptClass.Create('Raised by Mock');
      end;
      WillRaiseAlways : result := True;
      WillExecuteWhen :  result := MatchArgs;
      WillExecute     : result := True;
    end;
  end;

For some reason, in my code it falls through all that checking because there is only one parameter, the string. So, as far as TMock (and TBehaviour) is concerned, the method has no parameters and should therefore return the first WillReturn() for any call.

I hacked the code to check if the first parameter is indeed a object reference (I haven't worried about making sure it is indeed "self" yet), so it looks like this:

  function MatchArgs : boolean;
  var
    i : integer;
    LStartIndex: integer;
  begin
    result := False;
    LStartIndex := 0;
    if Args[0].Kind in [tkClass, tkInterface] then
      LStartIndex := 1;

    if Length(Args) <> (Length(FArgs) + LStartIndex) then
      exit;

    for i := LStartIndex to Length(args) -1 do
    begin
      if not FArgs[i-LStartIndex].Equals(args[i]) then
        exit;
    end;
    result := True;
  end;

I had to also change CopyArgs() to reflect the same change:

procedure TBehavior.CopyArgs(const Args: TArray<TValue>);
  var
    l : integer;
    LStartIndex: integer;
  begin
    LStartIndex := 0;
    if (Length(args) > 1) and (args[0].Kind in [tkClass, tkInterface]) then
      LStartIndex := 1;

    l := Length(args) - LStartIndex ;
    if l > 0 then
    begin
      SetLength(FArgs,l);
      CopyArray(@FArgs[0],@args[LStartIndex],TypeInfo(TValue),l);
    end;
  end;

I'm not sure yet how this will affect other parts of the Mocks library, it's just a quick hack to get me past my problem. I will update this issue as I come across problems and fix them.

Regards,

N@

Some units have (apparently unnecessarily) Windows in the uses clause

The following units have Windows in the implementation uses clause, apparently for no reason:

Delphi.Mocks.AutoMock
Delphi.Mocks.MethodData
Delphi.Mocks.Proxy
Delphi.Mocks.Proxy.TypeInfo
Delphi.Mocks.WeakReference

This prevents these units from being compiled for (for example) macOS

Mock Factory

Delphi-Mocks requires a factory for mock creation. This class simply defines default options to use when creating mocks.

Creating match any conditions in a WillReturn.When

Hi,

Not sure how to ask questions, but I want to be able to deal with any parameters in the following mocking setup.

mock.Setup.WillReturn(TValue.From(true)).When.DoIt(param1, param2);

Is there a way of doing this ?

Mocking an empty interface

I'm mocking the interface IPrincipalModelo that inherites from IModelo. When the test is running in DUnit, the moment the mock is created, this error is raised "class EMockNoRTTIException with message 'IPrincipalModelo does not have RTTI, specify {$M+}".

{$M+}
IPrincipalModelo = interface(IModelo)

end;
{$M-}

{$M+}
IModelo = interface

end;
{$M-}

If a method is inserted in IPrincipalModelo the test works. I know that it's not good to have an empty interface, so, what's should I do?

Mock/stub for classes with parametrized constructor

Hello,

I'm new user of Delphi Mocks. I'm trying to use mocks in my unit tests and I have problem. For example I want to create mock for class which derives from TComponent class. But when I'm trying to prepare mock using following code:
controlMock := TMock.Create;

it give me an exception: EInvocationError: Parameter count mismatch

Is it possible to create mock or stub for classes where constructor requires parameters? It would be very usefull for me.

best regards
Adam Siwon

Some questions rather than an issue

Using XE2, trying to compile latest Delphi-Mocks. In Delphi.Mocks...

  1. (many) TTypeInfo does not contain a member names 'NameStr'. (Should it be 'Name'?)
  2. (Line 182) class function Create(const ACreateObjectFunc: TFunc = nil): TStub; static;
    E2086 Type 'TFunc' is not yet completely defined
  3. Second implementation of ItRec.IsIn & ItRec.IsNotIn complains that identifier is redeclared
  4. (Lines 941, 942) 'TValue' does not contain a member named 'RttiType'

What am I missing?

No way to capture all method calls when parameters are required.

When there is a mock required for a class or interface and a setup is required on a particular method. If that method has parameters it becomes very hard to give the correct parameters to link the setup with.

For example if we have the following interface and class to mock.

type
  {$M+}
  IVisitor = interface;

  IElement = interface
    ['{A2F4744E-7ED3-4DE3-B1E4-5D6C256ACBF0}']
    procedure Accept(const AVisitor : IVisitor);
  end;

  IVisitor = interface
    ['{0D150F9C-909A-413E-B29E-4B869C6BC309}']
    procedure Visit(const AElement : IElement);
  end;

  TProjectSaveCheck = class(TInterfacedObject, IVisitor)
  public
    procedure Visit(const AElement : IElement);
  end;
  {$M-}

There is a problem trying to capture all calls to Visit, or even Accept. This means the following mock setup call needs to know the class or interface instance which is passed to the mock call.

var 
    mockVisitor : TMock<IVisitor>;
    element : IElement;
begin
    mockVisitor.Setup.Expect.Once.When.Visit(????);

    element.Accept(mockVisitor);

    mockVisitor.Verify;
end;

The above case has been reduced for brevity sake, the constructor has been removed. Also the element might be the instance to pass in. But if element has more children, and we were to visit all of them this would then make this call fail.

There needs to be away to specify conditions the parameters should meet for the expectation to be met, return result to be returned, etc.

It would be nice to be able to write something along the lines of:

mockVisitor.Setup.Expect.Once.When.Visit(Is.Any<IVisitor>);

I don't believe this is possible at present however as there is no way to reverse where the value came from. Also there is no generic way to override methods to have funcs defined for all parameters.

WillExecute crashes for safecall interface methods

I was trying to mock a COM typelib import interface which has safecall for all methods. This seems not to be supported by delphimocks as it crashes my application. At least it crashed when the method has more than one parameter.

Implement TMock<T>.Setup.BehaviorMustBeDefined

The Property BehaviorMustBeDefined on the ISetup-Interface isn't used anywhere.

I created an implementation which checks this flag on a method call and raise an error if no behavior is defined.

I added some code in "TMethodData.RecordHit" to check if there is an expectation, a behavior or a default return value. If none of this is true and BehaviorMustBeDefined is set, an exception is raised.

-> the tests fails when calling a method without an behaviour (not at the "verify"-method!)

Should I create a pull request for submitting this code?

Add funcationality to call "EqualsTo"-Method of a record

Creating expectations of methods which takes a records as parameter is not really possible, because the TValueHelper (Delphi.Mocks.Helpers) just compares the pointers of the records (which are almost unequal when using them as method parameters).

I created an implementation which tries to call the "Equal"-Operator of a record (if it is defined). If it is not possible to call this (e.g. the record has no rtti-information or no equal operator is defined), the current behavior is used (compare pointers).

Should I create a pull request to submit this code?

Allow multiple return values to be specified for a method

It would be really handy to be able to provide an array of TValues for the return values of a function so that on each call it will return the next value in the array.

This would remove the need to setup a will execute for the function and keep track of which call we are up to (which pollutes the code).

For example:

LListMock.Setup.WillReturnValues([-1, 2]).When.IndexOf(LItemMock);

Mock Objects

Does DelphiMocks allow the mocking of Objects or is it just interfaces? For example I'd like to mock a TIdHTTP component.

Setup.Expect.[...] crashes with TGUIDs

When using the Expect/Verify functionality in combination with a function, that has a TGUID-Parameter, an Access-Violation is guaranteed.

Here an example:

procedure TTest.TestGuid;
var
    guid: TGUID;
begin
    guid := TGUID.NewGuid;
    FMock.Setup.Expect.Once.When.SetGuid(guid); // Access Violation occures with this Expect
    FMock.Instance.SetGuid(guid);
    FMock.VerifyAll();
end;

For the full SSCCE, go here: PasteBin

TObjectProxy.Destroy raises "Invalid pointer operation".

After a test case, before the TearDown method, a exception EInvalidPointer with message 'Invalid pointer operation' is raised. The debugger show that a mock is being destroyed in TObjectProxy.Destroy. The mock is created on a class, not an interface, and this class implements two interfaces.

Not too much information, but this is what I got.

I really appreciate any help you can provide.

Not sure this is an issue - more of a question really

Hi

I am investigating the use of the Delphi Mock library on our legacy code - as a tool to test, and as a tool to drive the refactoring that I am doing.

However, quite a lot of the code I want to Mock is 'side-effecting', i.e when a method is called, it carries out some action on the server, and then returns true/false, but the function has also change data in the object. We then look at the data in that object, rather than what is returned from the methods.

So, should I Mock the entire object - which seem wrong as that is what I am testing - or is there another technique?

Thanks - and sorry if this is in the wrong place

Mark H

Mocked Object - Allow calling base class functionality

When mocking a class, an option should exists to call its base functionality.

A simple example of this is as follows;

var
  deud : TMock<TStringList>;
begin
  deud := TMock<TStringList>.Create;
  deud.Instance.Add('2');
end;

In the above code the mock deud should allow the add. Currently the add is not defined so an exception is raised. If the option to call base functionality is specified, an exception should only be raised on attempting to create a class with abstract members which are then called.

Wrong result for function behind index property (in XE2)

It seems to be similar to the open array issue.
I have made a testcase.
The expected value is the default for the function.
But what I get is the default for the property!
WORKAROUND: Moving the property to the end of the interface (minimum behind the function)
//####################################################################
unit Unit1;

interface
uses
Rtti,
Delphi.Mocks,
TestFramework, System.Classes;

type
imy = interface(IInvokable)
['{87D9C5DB-775A-4EA2-A10F-D9262CD8EA38}']
function GetProp(aIndex: integer ): integer;
function test_BEFORE_Property: integer;
property Prop[aIndex: integer]: integer read GetProp;
function test_BEHIND_Property: integer;
end;

TestMockup = class(TTestCase)
strict private
const TESTVALUE = 42;
private
fMock: TMock;
procedure inittest;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestMethodeBeforeIndexProperty_Ok;
procedure TestMethodeBehindIndexProperty_Error;
end;

implementation

procedure TestMockup.SetUp;
begin
inherited;
inittest();
end;

procedure TestMockup.TearDown;
begin
inherited;

end;

procedure TestMockup.TestMethodeBeforeIndexProperty_Ok;
begin
CheckEquals( fMock.Instance.test_BEFORE_Property, TESTVALUE );
end;

procedure TestMockup.inittest;
begin
fMock := TMock.Create();
fMock.Setup.WillReturnDefault( 'test_BEFORE_Property', TESTVALUE );
fMock.Setup.WillReturnDefault( 'Prop', -13 );
fMock.Setup.WillReturnDefault( 'test_BEHIND_Property', TESTVALUE );
end;

procedure TestMockup.TestMethodeBehindIndexProperty_Error;
begin
CheckEquals( TESTVALUE, fMock.Instance.test_BEHIND_Property );
end;

initialization
RegisterTest(TestMockup.Suite);

end.

Memory leak there should not have memory leak

Whe I turn on the memoryleak watcher, all tests are shown with leaked memory, but they shouldn't
This is the code:

procedure TestTNullJSONMarshal.NullObjectShouldBeNull;
var
  r: String;
begin
  r := '{"someObject":null}';
  Assert.AreEqual(r, '{"someObject":null}');
end;

I didn't create any objects, just used the "string".
This is the result:

leak

No warning or error reported for non-virtual method calls.

Currently if the following class is used for mocking;

type
    TMyClass = class(TObject)
        function NonVirtualFunc : boolean;
    end;

If the caller for TMock specifies a behavior or expectation on the NonVirtualFunc method they will not get any warning or error. Also their Verify call on the Mock will not fail as their are no registered expectations.

From what I can see this should be as simple as flagging in the Expect and Will*When calls that they were called. If the DoInvoke is not called after them then an exception is raised. This could be done on the reference release of the setup object. This shouldn't destroy the object as the Mock owns the proxy, however it should reduce the reference count by one.

This should remove an annoying bug where not having virtual declared on a method means you simply don't see the defined behavior being called.

Memory leak in TMock

Steps to reproduce:

  1. Include FastMM as first unit in the project
  2. Create test:
    procedure MyTest;
    var
      I: TMock<IMyInterface>;
    begin
      I := TMock<IMyInterface>.Create;
      I.Free;
    end;
    

Memory Leak using It0, It1, ... Matchers

I use the latest Delphi Mocks: 4b52b69,
additionally Spring4d and DUnitX

In my dpr file, I use

ReportMemoryLeaksOnShutdown := True;

to report memory leaks.

Now, I got the following testing class.

procedure TestLogger.Setup;
begin
  FTestContainer := TContainer.Create;

  FFilesystemMock := TMock<IFilesystemAdapter>.Create;
  FTestContainer.RegisterType<IFilesystemAdapter>.DelegateTo(
    function: IFilesystemAdapter
    begin
      Result := FFilesystemMock;
    end)
    .AsDefault;

  FTestContainer.RegisterType<TLogger>
    .Implements<ILogger>;

  FTestContainer.Build;


  FLogger := FTestContainer.Resolve<ILogger>;
end;

procedure TestLogger.TearDown;
begin
  FLogger := nil;

  FFilesystemMock.Free;

  FreeAndNil(FTestContainer);
end;

procedure TestLogger.TestLogInfo;
var
  aStream: TTestMemoryStream;
  aFileAsStr: string;
  aTimeStamp: string;
  aDummy: TDateTime;
begin
  // Arrange
  FFilesystemMock.Setup.WillReturn(True).When.DirectoryExists(It0.IsAny<string>, It1.IsAny<Boolean>);

  aStream := TTestMemoryStream.Create;
  aStream.OnDestroy := procedure(ASender: TObject)
    var
      aStringStream: TStringStream;
    begin
      aStringStream := TStringStream.Create;
      try
        aStream.Position := 0;
        aStringStream.CopyFrom(aStream, aStream.Size);
        aFileAsStr := aStringStream.DataString;
      finally
        FreeAndNil(aStringStream);
      end;
    end;

  FFilesystemMock.Setup.WillReturn(TValue.From<TStream>(aStream))
    .When.CreateFileStream(It0.IsAny<string>, It1.IsEqualTo<Word>(fmCreate or fmShareDenyWrite));

  // Act
  FLogger.LogInfo('TEST');

  // Assert
  aTimeStamp := Copy(aFileAsStr, 1, 23);
  Assert.IsTrue(TryStrToDateTime(aTimeStamp, aDummy));
end;

Hint: TTestMemoryStream.Create; is not the problem... it is freed by the system under test.

At the end of the testing process, I get the following error:

leakmsg

Is there anything I do wrong at using It0, It1, ... Matchers?
Or does Delphi-Mocks produce those leaks?

WillReturnDefault for stubs dont work anymore

It seems that the Values for WillReturnDefault for stubs dont work anymore.
The function TMethodData.StubNoBehaviourRecordHit never returns the value of FReturnDefault.
In a previous version the TMethodData.RecordHit returns the FReturnDefault directly, when no BestVehaviour would be found.
For mocks it works.

Compile issue when using WillReturnDefault against overloaded functions

Firstly, I want to say this is a great test framework and it helped a lot.
I had this issue not sure if it comes from Delphi-Mocks or other part.

I try to using WillReturnDefault against overloaded functions. And it doesn't compile as expected.
Here is the test code.

type
{$M+}
ITest = interface(IInterface)
['{5F3EF0EE-A4F4-4067-8DAC-1B9631BF0812}']
function GetName(const Name: string): IName; overload;
function GetName(const Name: string;
out Product: IName;
out ResultCode: string): Boolean; overload;
end;
{$M-}

mockName := TMock.Create;
mockTest := TMock.Create;
mockTest.Setup.WillReturnDefault('GetName', mockName.Instance); // Error goes here. E2010 Incompatible types

Then I tried following code, still not compile:

mockTest.Setup.WillReturn(mockName.Instance).When.GetName('Test'); // Error goes here. E2010 Incompatible types

I think there is a problem when the framework deal with overloaded functions.
I am using XE2.

Typos in Sample1Main.pas

Sample1Main.pas

Line 111: //we expecte bar...
"expect" not "expecte"

Line 132: 'Calling Bar(2,sdfsd) : '
999 not 2 ( or perhaps 099 not 999 - so the expectation would be met later?)

Need research if IStubSetup<T> can benefit from an overloaded method function WillReturn<TReturn>(const value : TReturn) : IWhen<T>; overload;

Right now I've quite some places with code like this:

procedure TMyProxyTests.GetStatus;
var
  lSubject: IMyInterface;
  lStatus: TMyRecord;
  lStatusValue: TValue;
  lMock: TMock<IMyInterface>;
begin
  lMock := TMock<IMyInterface>.Create();
// already complex lStatus initialisation
  lStatusValue := TValue.From(lStatus);
  lMock.Setup.WillReturn(lStatusValue).When.GetStatus();
  lMock.Setup.Expect.Once.When.GetStatus();
  lSubject := TMyProxy.Create(lMock);
  lSubject.GetStatus();
  lMock.Verify();
  Assert.Pass();
end;

It might be that if IStubSetup<T> has an overloaded method function WillReturn<TReturn>(const value : TReturn) : IWhen<T>; overload; that this code becomes more readable.

Need to try this out and see if there are no drawbacks (like the compiler choosing the wrong overload)

Add "function WillReturn<TReturn>(const AValue : TReturn) : IWhen<T>;" to TProxy<T>

Currently in my mocking there is a great deal of writing the following;

myMock.Setup.WillReturn(TValue.From<SomeType>(instanceOfType)).When.MyMethod;

This would be a little nicer to write as

myMock.Setup.WillReturn<SomeType>(instanceOfType).When.MyMethod;

To do this TProxy would require the following function to be added.

function WillReturn<TReturn>(const AValue : TReturn) : IWhen<T>;

Will look at adding this over the next day or so... unless someone else gets to it before me.

Include FHitCount in TExpectation.Report

Hi Folks,

it would be nice to have the real values next to the expected values, where it makes sense, since this can help to locate the reason for a test failure.

Something along the lines of:

function TExpectation.Report: string;
begin
  result := '';
  if not FExpectationMet then
    begin
      case FExpectationType of
        Once:
          result := 'Once. Was ' + IntToStr(FHitCount);
        Never:
          result := 'Never. Was ' + IntToStr(FHitCount);
...

would come in handy

Question: How to mock a method that passes a parameter by reference?

I have a method (function) that has two arguments and returns an integer. The first argument is passed by value and the second by reference (var). I would like to mock what this method should pass back on on the second argument. First, the closest thing I can see to accomplish this is to use WillExecute. However this only passes my method's arguments in as const. I am setting the result of my TExecuteFunc equal to args[0]. I would like to set args[1] equal to some value.

How to mock, or stub, a method that has one or more arguments that are passed by reference? I am wanting to test the argument that is passed by reference. The CUT has a method that that passes an argument by reference.

MockDap.Setup.WillExecute(function (const args : TArray<TValue>; const ReturnType : TRttiType) : TValue begin result := args[0]; args[1] := Expected; end).When.GetDAPData(TheLength, Actual);

Thanks

Mock does not behave correct

A mock that does not have any expectations defined for a method behaves like a stub and does not report this method in Verify.

See the Sample1Main.Test.
I would expect the mock to complain directly or at least when calling Verify
about unexpected calls to SetMyProp and SetMyIndexedProp.

I also would expect that the call Bar(2) would be complained about because it has no expectation defined anywhere.

Get rid of W1029 warning in Delphi compile mode

Currently the compilation results in a lot of W1029 warnings that are only relevant for C++ code; see the compiler output below.

This might be as simple as {$WARN SYMBOL_DEPRECATED OFF} before and {$WARN SYMBOL_DEPRECATED ON} after the code (I don't think Delphi has a $IFWARN construct like it has $IFOPT and I'm not sure how to set compiling in Delphi and C++ mode apart; the last might be moot if Delphi-Mocks cannot be used from C++).

For completeness some references:

Compiler output:

[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAfter' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAfterWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtLeastOnce' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtLeastOnceWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtMost' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtMostWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateExactly' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateExactlyWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateNever' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateNeverWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateOnce' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateOnceWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAfter' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAfterWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtLeastOnce' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtLeastOnceWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtMost' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateAtMostWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateExactly' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateExactlyWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateNever' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateNeverWhen' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateOnce' with identical parameters will be inacessible from C++
[dcc32 Warning] W1029 Duplicate constructor 'TExpectation.CreateOnceWhen' with identical parameters will be inacessible from C++

Add TStub that is simpler and doesn't do anything

Current testing wisdom says that there are two kinds of fakes, Mocks and Stubs. It's probably too late to change this project's name to "Delphi Isolation Framework", but may I suggest that we add a TStub to the project?

TStub would stand in for any class or interface and basically do nothing but "be" the class or interface that it is designed for.

This would enable the framework to be clearer about the purpose of a given fake inside of a test.

Thoughts?

Memory Leak in TInterfaceProxy

To Reproduce:
Build Project with Fastmm
In code Make something like a
TMock.Create.Free;

Here is a Fix:
Index: Delphi.Mocks.InterfaceProxy.pas

--- Delphi.Mocks.InterfaceProxy.pas (Revision 10624)
+++ Delphi.Mocks.InterfaceProxy.pas (Revision 10625)
@@ -75,8 +75,8 @@
begin
inherited;
FVirtualInterface := TProxyVirtualInterface.Create(Self,TypeInfo(T),Self.DoInvoke);

  • //remove reference created in this constructor, the virtual interface and proxy's lifetime are now the same.
  • FVirtualInterface._Release;
  • //remove reference created in this constructor, the virtual interface and proxy's lifetime are now the same.
  • Self._Release;
    end;

destructor TInterfaceProxy.Destroy;
@@ -132,11 +132,13 @@
function TInterfaceProxy.TProxyVirtualInterface._AddRef: Integer;
begin
result := FProxy._AddRef;

  • inherited;
    end;

function TInterfaceProxy.TProxyVirtualInterface._Release: Integer;
begin
result := FProxy._Release;

  • inherited;
    end;

end.

Self referring class/interface functions return nil for return type.

The following class declaration. (Split out to highlight use of forward declaration.)

 {$M+}
  ISelfReferencingInterface = interface;
  {$M-}

  {$M+}
  ISelfReferencingInterface = interface
    ['{82812243-3A98-4446-A2FD-81705E8E5727}']
    function ReturnSelf : ISelfReferencingInterface;
  end;
  {$M-}

mock.Setup.WillReturn(TValue.From<ISelfReferencingInterface>(mock)).ReturnSelf;

The rtti returned for the DoInvoke call of ReturnSelf, for XE5 and below, has the return type as nil. This currently causes an exception to be raised by the Mock framework for WillReturn, etc. From testing this seems to be fixed in XE6 and above.

Current thinking is that the rtti information would need to be patched for the function if it is to be mocked in XE5 and below.

This is possible with the ReturnTypePatch unit at present.

The extension to this would be to automatically test all methods in XE5 and below, then patch them. Throwing an error if the patch is required and no attribute is required. This is messy, however as the rtti is incorrectly returned the solution won't be as neat.

Access Violation when mocking an Interface with an event handler

I have been debugging a unit case all day and finally narrowed it down to using a Mock of a interface with an event handler. For example the following code of a console program fails but only when I have an event with another interface in the parameter:

program MockFail;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Delphi.Mocks,
  System.SysUtils;

type

    {$M+}
    ITest = Interface
      ['{5698E196-A737-4D88-BA4C-1EFB8CF48998}']
    End;

   TMyEvent = procedure(Sender:TObject; Test: ITest) of Object;

    IFoo = Interface
      ['{F59F92E4-FF76-4F6C-8841-D21BEAD65CE3}']
      function getDateTime : TDateTime;

      function getMyEvent : TMyEvent;
      procedure setMyEvent(const Value: TMyEvent);
      property OnMyEvent : TMyEvent read getMyEvent write setMyEvent;
      function getName : String;
    End;

var
    MockFoo : TMock<IFoo>;
begin
  try
     MockFoo := TMock<IFoo>.Create;
     MockFoo.Setup.WillReturn(Now).When.getDateTime;
     MockFoo.Setup.WillReturn('This line fails').When.getName; // <---- Fails with an Access Violation
     WriteLn(DateTimeToStr(MockFoo.Instance.getDateTime));
     WriteLn(MockFoo.Instance.getName);
     Readln;
  except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);
      Readln;
    end;
  end;
end.

A workaround has been to remove the "property" line of the interface. I don´t know if its a Delphi bug or a Delphi Mocks bug. Thanks in advance

Calling mocked safecall method corrupts stack

If try to call mocked safecall method, this call corrupts stack, and after several calls it leads to unpredictable exceptions.

Code for reproducing:

program TestStackError;
{$APPTYPE CONSOLE}

uses
  Delphi.Mocks;

type
{$M+}
  ITestee = interface
    procedure SomeMethod; safecall;
  end;
{$M-}

var
  m : TMock<ITestee>;
  I: Integer;
begin
  m := TMock<ITestee>.Create;
  for I := 0 to 10000 do
    m.Instance.SomeMethod;
end.

This happens in XE2 & XE7 Win32

Also this seems to be related to issue #8 , however, this one seems to be much broader

What are differences between TMock and TStub?

I see these usages in procedure Test of unit Sample1Main:

mock : TMock; //our mock object
stub : TStub; //our stub object;

Is there any different between TMock and TStub? When to use TMock or TStub?

Privileged instruction with methods which have a dynamic array as parameter

DUnit unit test which reproduces the issue here: https://gist.github.com/fabioxgn/4965639

It will raise a privileged instruction in XE2 and a AV in XE3, it is raised in the Delphi.Mocks.Helpers SameValue method.

Looks like a Delphi bug to me, when I try to read the Left.Kind a get an "out of bounds" and a different number each time.

With a typed array the example works fine, as showed in the dunit test.

Another weird thing is that if the method only have the dynamic array as a parameter, it works. It just crashes when I add a second parameter to it.

Status of Delphi XE support

I looked at this awhile ago and saw the reasons why XE wasn't supported. The comments alluded to a workaround for the (if I remember correctly) TVirtualMethodInterceptor, but when I got into trying to make it work, I quickly saw why it was likely not in place. I know XE support is not on any priority list, but if there HAS been any progress, or if someone can point me in the right place on how to fix the primary issue, it might be something I can handle and test out. Mocking manually (especially knowing there is a better way) is definitely no fun, but I can't move off of XE at this point for the main application I develop.

Unit tests fails with latest DelphiMocks in Delphi XE2

Hi again, I updated DelphiMocks to the latest commit however I started to receive exceptions about RTTI not enabled in my interfaces. Trying to check if it was my code or something else I opened the unit tests but those fail too. Te failed tests are:

  • CheckInterfaceHasRTTIWithNonInterface
  • CheckInterfaceHasRTTIWithInterfaceRTTI

My system is:

  • Windows 7 64 bits
  • Delphi XE2 with Update 4.

Plugins installed:

  • EurekaLog7 (disabled in test projects)
  • Jedi Libraries.

UPDATE: The problem seems to be with Delphi.Mocks.Utils.pas specifically the method "CheckInterfaceHasRTTI", when I use this file commit:
https://github.com/VSoftTechnologies/Delphi-Mocks/blob/1fb6ea3175e4c028bcc7df5cc7c649d8de4c78dd/Delphi.Mocks.Utils.pas the problem no longer occurs.

Thanks in advance for your help.

AutoMock Class

A mock generator which is used by TMock. It no generator is present then the current behavior is used.

When the AutoMock is used to build a mock, all instances which that mock hits which are required by not specified are automatically mocked.

Calling setup for a particular type, will also create a mock of that type.

Each time a new instance is referenced a new mock is created. For example if there is a list of items off the mocked object/interface, each index referenced would get its own mock.

This feature would allow specifying only what is important to the test. Leaving everything else to automatically be created.

Problem with mock in Win64 mode.

Hello,

I have problem with using mocks in code compiled to Win64 platform. I wrote small example app which shows wrong values returned by mock:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    function TestDouble: Double;
    { Private declarations }
  public
    { Public declarations }
  end;

  ITest = interface(IInvokable)
    ['{DE3ACD58-A748-4528-A2A6-13C7A9247DB2}']
    function GetDate: TDateTime;
    property Date: TDateTime read GetDate;
  end;

var
  Form1: TForm1;

implementation

uses
  Delphi.Mocks;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  mock: TMock<ITest>;
  test: ITest;
begin
  mock := TMock<ITest>.Create;
  mock.Setup.WillReturn(Date).When.GetDate;
  Button1.Tag := Trunc(TestDouble);
  test := mock;
  Button1.Caption := DateToStr(test.GetDate);
end;

function TForm1.TestDouble: Double;
begin
  Result := 123;
end;

After execution of the Button1Click procedure caption of the button is changed to wrong value (1900-05-02 value 123 in date format) when app is compiled for Win64 platform. When application is compiled for Win32 platform value is correct (current date). I think this is not Delphi Mocks related problem but TVirtualInterface related problem. Maybe it is corrected in newer version of Delphi. I'm using Delphi XE4 Pro.

Access Violation when creating a stub in a different method

I'm not really sure if this is a Delphi (maybe TVirtualInterface) or a Delphi-Mocks bug, but a TStub is prematurely freed when it is created on a different method.

I came to the conclusion after hours of debugging.... to make a long story short, let's the code talk for me:

Given this interfaces:

  IBar = interface(IInvokable)
    procedure DoNothing;
    procedure DoNothingWithParam(X: Integer);
    function GetNothing: string;
  end;

  IFoo = interface(IInvokable)
    procedure SetBar(Value: IBar);
    function GetBar: IBar;
    property Bar: IBar read GetBar write SetBar;
    procedure UseBar;
  end;

I have a TestFoo TestCase, with this methods (DUnit)

//private methods, just to show the _bug_
procedure TestIFoo.SetupBar;
begin
  //this creates a real object implementing the Interface
  FIFoo.Bar := UBarImpl.GetBar;
end;

procedure TestIFoo.SetupStub;
begin
  FIFoo.Bar := TStub<IBar>.Create;
end;

//published tests, which call the above methods:

procedure TestIFoo.TestUseBar_SetupBar_WithCall;
begin
  SetupBar;
  FIFoo.UseBar;
end;

procedure TestIFoo.TestUseStub_SetupStub_WithCall;
begin
  SetupStub;
  FIFoo.UseBar;
end;

The TFoo relevant methods looks like this:

procedure TFoo.SetBar(Value: IBar);
begin
  FBar := Value;
end;

procedure TFoo.UseBar;
begin
  CheckConfigured;
  if FBar.GetNothing = '' then
    FBar.DoNothingWithParam(1);
end;

image

As you can see, the TestUseBar_SetupBar_WithCall test (using real object implementing the interface) is succeeding, while the TestUseStub_SetupStub_WithCall (using a TStub) is failing with an EAccessViolation error.

The AccessViolation occurs in the first interface use inside the UseBar method.

What I can see is the TStub is being prematurely freed when the TestIFoo.SetupStub ends, and that's because the Reference count is not being incremented (no call to _AddRef) when the interface is assigned to the FBar field inside the TFoo.SetBar method, whereas the real object reference count gets incremented on that same line.

XE7 issue with mocked private methods

We are moving from XE5 to XE7. We have several tests that worked fine in XE5 but are breaking in XE7. Specifically using WillExecute no longer seems to work for Protected and Private methods.

We have code similar to the following...

FMockDO : TMock;

FMockDO.Setup.WillExecute( 'GetDataset',
function (const args : TArray; const ReturnType : TRttiType) : TValue
begin
case RefCnt of
1: Result := FCDS1;
2: Result := FCDS2;
end;
end
);

TDataObject is declared as the following

{$RTTI EXPLICIT METHODS([vcPublic, vcPublished, vcProtected, vcPrivate]) PROPERTIES([vcPublic, vcPublished])}
TDataObject = class( TComponent )
private
...
protected
...
function GetDataset: TDataset;virtual;
...
public
...

If I move the GetDataset method to the public section the test runs just fine.

For now we have created a hack class that promotes the visibility of that method for testing, but wanted to report the regression.

Thanks
MGallaher

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.