I have an interface function that has a constant array and an anonymous function as parameters:
TCodeword = array[0..7] of Char;
TIntFunc = reference to function: Integer;
IMyInterface = interface(IInvokable)
function DoSomething(const codeword: TCodeword; func: TIntFunc): Boolean;
end;
I want to mock that interface to test an object, that is using it:
function IntFunc: Integer;
begin
Result := 5;
end;
procedure Test;
var
MyInterfaceMock: Mock<IMyInterface>;
MyInterface: IMyInterface;
begin
MyInterfaceMock := Mock<IMyInterface>.Create(TMockbehavior.Strict);
MyInterfaceMock.Setup.Returns(true).When.DoSomething(arg.IsAny<TCodeword>, arg.IsAny<TIntFunc>());
MyInterface := MyInterfaceMock;
MyInterface.DoSomething('12345678', IntFunc);
end;
When running, an ENotSupportedException: ‚Type is not supported: TCodeword‘ is raised when Setup. Can somebody explain why this is a not supported type? How can I pass a not specified TCodeword to mock that function correctly?
Alternatively I tried to pass explicit arguments in Setup:
procedure Test;
var
MyInterfaceMock: Mock<IMyInterface>;
MyInterface: IMyInterface;
begin
MyInterfaceMock := Mock<IMyInterface>.Create(TMockbehavior.Strict);
MyInterfaceMock.Setup.Returns(true).When.DoSomething('12345678', IntFunc);
MyInterface := MyInterfaceMock;
MyInterface.DoSomething('12345678', IntFunc);
end;
That way it will work for the constant array but not for the anonymous function. I get an EMockException: 'unexpected call of function DoSomething(const codeword: TCodeword; func: TIntFunc): Boolean with arguments: nil, (array)';
How can I make this work? I am glad for any help!
CodePudding user response:
There are multiple issues:
as the exception states the
TCodeword
type is not supported - that is because types of typeKindtkArray
are not supported - I don't remember exactly why that is because internally the handling is very similar to tkDynArray. I will fix that and put an edit to this answer once done.when passing a regular function to a method reference parameter the compiler builds the necessary code to wrap the regular function into a method reference and it uses an interfaced object for that which implements the interface of the method reference (after all anonymous methods are just interfaces). It however does that for every time this happens which means that two lines that pass
IntFunc
to anTIntFunc
parameter are two different pointers. That is why internally the parameter matcher returns False. If you want to avoid that you need to putIntFunc
into a local variable of typeTIntFunc
and pass that. Because then the compiler only builds that wrapping code once and in both cases the value of the local variable gets passed to theDoSomething
call.
Update: fixed in develop branch