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!
DSharp Mocks does not support all types for param matching (see
SameValue
inDSharp.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.