What is the best way to setup Delphi DSharp mocks with Nullable types from the Spring framework? I've tried various approaches and I know I'm probably missing something really rudimentary, but I just can't figure out how to get the following code to work:
program DSharkMockNullable;
{$APPTYPE CONSOLE}
{$R *.res}
uses
DSharp.Testing.Mock,
Spring,
System.SysUtils;
type
{$M+}
IBaseMock = interface
['{B3311345-3C1F-47E3-8235-57B1BA04E957}']
function GetId: TNullableInteger;
procedure SetId(Value: TNullableInteger);
property Id: TNullableInteger read GetId write SetId;
end;
{$M+}
IMockMe = interface(IBaseMock)
['{07F8F233-E8F5-4743-88C5-97A66BB01E29}']
function GetObjectId: TNullableInteger;
procedure SetObjectId(Value: TNullableInteger);
property ObjectId: TNullableInteger read GetObjectId write SetObjectId;
function GetObjectName: TNullableString;
procedure SetObjectName(Value: TNullableString);
property ObjectName: TNullableString read GetObjectName write SetObjectName;
end;
TMyObject = class
public
function ObjectIdAsString(const AObject: IMockMe): string;
end;
{ TMyObject }
function TMyObject.ObjectIdAsString(const AObject: IMockMe): string;
var
LId: Integer;
LObjectId: Integer;
LObjectName: string;
begin
LId := AObject.Id; // ***** FAILS HERE with an "Invalid Typecast" error
LObjectId := AObject.ObjectId;
LObjectName := AObject.ObjectName;
Result := Format('Id: %d', [LId]);
Result := Format('Object Id: %d', [LObjectId]);
Result := Format('Object Name: %s', [LObjectName]);
end;
var
LMock: Mock<IMockMe>;
LObject: TMyObject;
begin
try
LMock.Setup.WillReturn(123).Any.WhenCalling.Id;
LMock.Setup.WillReturn(456).Any.WhenCalling.ObjectId;
LMock.Setup.WillReturn('blahblah').Any.WhenCalling.ObjectName;
LObject := TMyObject.Create;
Writeln(LObject.ObjectIdAsString(LMock.Instance));
LObject.Free;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Any ideas or suggestions would be great? I'm using Delphi XE5. Thanks. Rick.
The correct code should look like this (not using type inference):
As addition to the correct answer that Rick already gave here some explanation why that is the case:
The original code uses type inference for the values passed to WillReturn and it infers them as
ShortInt
,SmallInt
(compiler uses the smallest signed ordinal type that fits) andstring
. These are stored asTValue
and returned when the method is being called. But then the RTTI tries to cast theTValue
to the return type and the method which fails because it does not know how to cast aShortInt
orSmallInt
to aNullable<Integer>
or astring
to aNullable<string>
sinceTValue.TryCast
does not know about any Implicit operator overloads of theNullable<>
type and there is no way to register any custom converters.