Mocking fails for Spring.Collections descendant interfaces
Good day, Stefan!
I faced the following issue when migrating projects from 1.2.6 to version 2.0:
Mocks for interfaces descendant from Spring.Collections (like interface(IDictionary<K,T>)) does not work anymore even if I add M+.
program Project1;
uses
Spring.Mocking,
Spring.Collections;
type
IMyDict = interface(IDictionary<Integer, String>)
['{C585B00C-AB3F-4414-B3AE-01C34FA8AE16}']
procedure NewMethod;
end;
var
LMock: Mock<IMyDict>;
begin
LMock.Setup.Executes.When.NewMethod;
end.
It works flawlessly with 1.2.6. Is this some conceptual change in the collections or am I missing something?
Kind regards, Zigmund.
Comments (8)
-
reporter -
reporter Also when the mock behaviour is dynamic the methods which before returned mocked instance if setup was not provided return nil for spring.collections types.
-
reporter Implicit conversion in Setup.Returns(X).When.CreateNullableX does not work as well. So in version 1.2.6 we could write an underlying record type in returns for the method which returns nullable of that record. in 2.0 this does not work anymore (in one case there was even an exception on line where such a setup was done). Was this feature dropped now in 2.0 and now we always need to do Returns<Nullable<TRecord>>(LRec).When.CreateNullableTRecord?
-
repo owner Is this some conceptual change in the collections
Yes, it is - collection interface types have RTTI turned off to reduce code bloat because 99% it’s not needed.
Adding {$M+} does indeed work:
uses System.SysUtils, Spring.Mocking, Spring.Collections; type {$M+} IMyDict = interface(IDictionary<Integer, String>) ['{C585B00C-AB3F-4414-B3AE-01C34FA8AE16}'] procedure NewMethod; end; {$M-} var LMock: Mock<IMyDict>; begin try LMock.Instance.NewMethod; LMock.Received(Times.Once).NewMethod; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
You can however turn it back on by modifying Spring.Collections.pas For other issues (although related) please file a separate issue and don’t put them into “oh, by the way” comments, thank you :)
-
repo owner - changed status to closed
-
reporter Thank you for your reply. There is just quite a lot of places in the unit tests where methods return IList, IDictionary and they were never setup explicitly. Seems that now we are forced to do so.. or maybe we will make some conditional to generate RTTI for unit test projects, but not for production..
-
repo owner FWIW I have looked after passing type
T
toReturns
when the method returnsNullable<T>
and from what I can see this works.The code that handles this is in
CastToReturnType
inSpring.Mocking.Interceptor.pas
- if you have some code to repro this issue please file this as new issue, thank you. -
reporter Adding {$M+} does indeed work:
Only for methods defined in the descendant interface (NewMethod). Once trying to verify mock or setup on methods from
IDictionary<Integer, String>
it fails with EInsufficientRtti - because as you already mentioned there is no RTTI anymore for collections. - Log in to comment
Forgot to mention (if of any importance) we are using Delphi 11.3