2

When using record types in a Delphi DUnit test with DSharp Mock for an interface, it is throwing and Unexpected Invocation but I cannot figure out why? I have created test console app below.

program ConsoleStuff;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  DSharp.Testing.Mock,
  DUnitTestRunner,
  Spring,
  TestFramework,
  System.SysUtils;

type

  {$M+}
  IMyType = interface
  ['{D3F69229-1B46-4FE2-B078-80AA313FB601}']
    function GetNullableSingle: Nullable<Single>;
    function GetSingleValue: Single;
    procedure SetNullableSingle(const Value: Nullable<Single>);
    procedure SetSingleValue(const Value: Single);
    property NullableSingle: Nullable<Single> read GetNullableSingle write SetNullableSingle;
    property SingleValue: Single read GetSingleValue write SetSingleValue;
  end;

  TMyType = class(TInterfacedObject, IMyType)
  private
    FNullableSingle: Nullable<Single>;
    FSingleValue: Single;
    function GetNullableSingle: Nullable<Single>;
    function GetSingleValue: Single;
    procedure SetNullableSingle(const Value: Nullable<Single>);
    procedure SetSingleValue(const Value: Single);
  public
    property NullableSingle: Nullable<Single> read GetNullableSingle write SetNullableSingle;
  end;

  TMyOtherType = class
  private
    FMyType: IMyType;
  public
    constructor Create(const AMyType: IMyType);
    procedure SetMyTypeValue(const AValue: Nullable<Single>);
  end;

  TMyOtherTypeTests = class( TTestCase)
  published
    procedure UnexpectedInvocation;
  end;

{ TMyType }

function TMyType.GetNullableSingle: Nullable<Single>;
begin
  Result := FNullableSingle;
end;

function TMyType.GetSingleValue: Single;
begin
  Result := FSingleValue;
end;

procedure TMyType.SetNullableSingle(const Value: Nullable<Single>);
begin
  FNullableSingle := Value;
end;

procedure TMyType.SetSingleValue(const Value: Single);
begin
  FSingleValue := Value;
end;

{ TMyOtherType }

constructor TMyOtherType.Create(const AMyType: IMyType);
begin
  FMyType := AMyType;
end;

procedure TMyOtherType.SetMyTypeValue(const AValue: Nullable<Single>);
begin
  FMyType.SetSingleValue(AValue.Value);  // This works OK
  FMyType.SetNullableSingle(AValue);     // This DOES NOT work
end;

{ TMyOtherTypeTests }

procedure TMyOtherTypeTests.UnexpectedInvocation;
var
  LMyOtherType: TMyOtherType;
  LMyType: Mock<IMyType>;
begin
  LMyType.Setup.WillExecute.Once.WhenCalling.SetSingleValue(Nullable<Single>.Create(10));      // This is OK
  LMyType.Setup.WillExecute.Once.WhenCalling.SetNullableSingle(Nullable<Single>.Create(10));   // This is NOT OK
  //LMyType.Setup.WillExecute.Once.WhenCallingWithAnyArguments.SetNullableSingle(Nullable<Single>.Create(10));   // This line WORKS OK
  LMyOtherType := TMyOtherType.Create(LMyType);
  LMyOtherType.SetMyTypeValue(Nullable<Single>.Create(10));
  LMyType.Verify;
end;

begin
  try
    RegisterTests('TMyOtherType', [TMyOtherTypeTests.Suite]);
    DUnitTestRunner.RunRegisteredTests;
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

The tests works ok with "WhenCallingWithAnyArguments" method, but I really need the "WhenCalling" method to check the value being assigned to the property setter.

I've used the Nullable<> type for demo purposes only and other Record types also fail.

Please help!

Rick Wheeler
  • 1,142
  • 10
  • 22

1 Answers1

3

DSharp Mocks does not support all types for param matching (see SameValue in DSharp.Core.Reflection).

You can certainly fix that but I suggest you migrate to Spring.Mocking which has a slightly different API but provides param matching for all types and is way more powerful.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • Thanks for the quick reply Stefan. Is there any doco on the Spring.Mocking library? Would like to check it out but need some help getting started and the sample project doesn’t appear to be compiling. – Rick Wheeler Jul 01 '21 at 09:54
  • All use cases should be handled in `Spring.Tests.Mocking.pas` – Stefan Glienke Jul 01 '21 at 10:14
  • 1
    Thanks Stefan! I've been out of Delphi for a couple of years and didn't know this new Sping.Mocking library existed. Awesome job it is much simpler and cleaner the DSharp. Big kudos! – Rick Wheeler Jul 01 '21 at 10:46