2

As the title suggests, I'm trying to write a test to verify that one version of a method is called, and that the overloaded version is not. Since Delphi-Mocks seems to use indexing on the parameter matching, I'm seeing a fail, and that the the overloaded function is being called when it is in fact, not.

Sample Test Interface

TFoo = class(TObject)
public 
    function Bar(const a, b, c: string) : string; overload;virtual;
    function Bar(const a: string) : string; overload;virtual;
end;

Sample Test Code

procedure TestClass.Test
var mock : TMock<TFoo>;
    bar : TBar;
begin
    mock := TMock<TFoo>.Create;
    bar := TBar.Create(mock);
    mock.Setup.Expect.Once.When.Bar('1','2','3');
    mock.Setup.Expect.Never.When.Bar(It(0).IsAny<string>());        

    //Will Wind up down an if-branch calling either bar(1) or bar(3)
    bar.Execute; 

    mock.VerifyAll;        
end;

Thanks!

mwilkinson
  • 97
  • 1
  • 7

2 Answers2

2

FWIW in Spring Mocks (part of the upcoming 1.2 release) the same test would look like this:

procedure TestClass.Test;
var
  mock: Mock<TFoo>;
  bar: TBar;
begin
  foo := TBar.Create(mock);

  bar.Execute; 

  mock.Received(1).Bar('1', '2', '3');
  mock.Received(0).Bar(Arg.IsAny<string>);
end;

As you noticed the concept is a bit different. If you are running with the mock behavior dynamic (which is the default) every call to the mock is allowed and returns the default for functions (like empty string, 0 or nil). Afterwards you can use Received to check if the methods where called the expected times.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • mock.Received throws an exception though, which is not recognized by DUnitX as an assertion failure. So this code would show a test as 'Errored' rather than 'Failed'. Anything that can be done about that, apart from wrapping this in `Assert.WillRaise(...)`? – GolezTrol Oct 19 '18 at 14:07
  • Same is the case for DUnit and Delphi-Mocks in any combination iirc. So either the test framework would need to have a mechanism to tell it about any particular exception types that are not an error but a failure or the mock framework would need to use the test frameworks test failure exception. I don't expect this to be supported out of the box but on your side you can simply solve this by letting EMockException (I think Delphi-Mocks calls it the same) inherit from ETestFailure (also iirc DUnit and DUnitX call it like that) in your local copy of the code. – Stefan Glienke Oct 19 '18 at 14:47
  • Didn't work much with the others, but yeah. It can be solved by wrapping the call to `mock.Received` in a call to `Assert.WillRaise(procedure begin mock.Received() end, EMockException)`, but that's quite convoluted. DUnitX.Assert allows you to set the exception which Assert throws, but it still has to descend from ETestFailed, because that's what the framework looks for. In Spring Mocks, I can't set any exception class or factory at all. Messing with the ancestry (either in code or at runtime) seems to be the only way. Or just accept having to wrap it in a call to `Assert.WillRaise`... – GolezTrol Oct 19 '18 at 23:18
1

You can use "WillExecute" to check this. For example:

procedure TestClass.Test;
var
  mock : TMock<TFoo>;
  bar : TBar;
  CheckPassed: Boolean;
begin
  mock := TMock<TFoo>.Create;
  bar := TBar.Create(mock);

  CheckPassed := True;
  mock.Setup.WillExecute('Bar',
    function(const Args: TArray<TValue>; const ReturnType: TRttiType): TValue
    begin
      if Length(Args) = 2 then // one is for "Self"
        CheckPassed := False;
    end);

  //Will Wind up down an if-branch calling either bar(1) or bar(3)
  bar.Execute;

  Assert(CheckPassed);
end;
GolezTrol
  • 114,394
  • 18
  • 182
  • 210
Michael Izvekov
  • 196
  • 1
  • 5