This point is on the roadmap.
]]>With TVirtualInterface I can create something like this (quick & dirty implementation):
TVirtualInterface.Create(TypeInfo(IMyInterface),
procedure(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue)
var
LArgs: TArray<TValue>;
i: Integer;
begin
SetLength(LArgs, Length(Args) - 1);
for i := Low(LArgs) to High(LArgs) do
LArgs[i] := Args[i + 1];
Result := Method.Invoke(TValue.From<IInterface>(instance), LArgs);
end).QueryInterface(IMyInterface, proxy);
I would expect NIL if not assigned.
]]>I do not see how we may do it for interface-based services easily.
How should we know how to implement serialization of the interface? Using its underneath object? Then instantiate it on the other side with the proper interface definition?
Could be done, but a lot of work.
For Client-Server access, the mORMot preference is to use either plain classes, either value objects (i.e. records).
For stubbing/mocking, we may add handling of tkMethod/tkInterface kind of parameters, then use a dedicated method to provide the expected instances.
I've added a "Feature Request" for it.
http://synopse.info/fossil/tktview/155d58506
What should be the default value for such interface? I suspect, just nil.
Thanks for the feedback.
]]>I am using Delphi 6 and source code from 23rd January.
First I define 2 interfaces. Interface I2 has a property which is of type I1.
type
I1 = interface( IInvokable )
['{FDF97D0F-9290-44C2-AD2B-48C87EF9F8EA}']
end;
I2 = interface( IInvokable )
['{904BC00C-2745-4C12-B09C-D841627BC7AF}']
procedure Set_I( value: I1 );
property I: I1 write Set_I;
end;
I then create a Mock.
procedure DoTest;
var
iii : I2;
begin
TInterfaceMock.Create( TypeInfo( I2 ), iii, NIL );
end;
This breaks in the interface factory because TypeInfoToMethodValueType returns smvNone as the typeValue. Looking at this method, it does not recognise interfaces as a type.
ValueType := TypeInfoToMethodValueType(TypeInfo);
case ValueType of
smvNone: begin
case TypeInfo^.Kind of
...
end;
raise exception.....
end;
I have read some of the blog and documentation and cannot see any reference to this. I am not sure what the code does and if this is something you dont need, so have not implemented or if there is a problem with implementing it.
Also, it is the same with a tkMethod Kind. As I also pass Event Handlers in interfaces.
Edit:
I have done some further looking into it and I see it is because you store information as JSON through the textwriter class. But you store instance pointer along with the classname. Is it possible to add a new method to this class to store interface pointer and interface type? Then send back the interface when method is called?
Sorry if this should be a new topic, if it should, please let me know
]]>Honestly, I'm still not convinced by the parameters dummy values to be set.
Is it worth it?Most tests (i.e. just stubbing a method without any parameters expectations) will be more difficult and verbose to write IMHO.
I think it depends on what you are doing ("Mocks aren't stubs")
and how restrictive and specific you want to use a mock and its expectations.
Most tests (i.e. just stubbing a method without any parameters expectations) will be more difficult and verbose to write IMHO.
]]>My concern is that you can not just call SmsSender.Send() with no parameters...
Two possibilities:
- Make all parameters optional (may introduce issues);
- Force putting some parameters (code will inflate and be difficult to write).How to resolve this?
Imo the benefit of having to pass the parameter is that you can easily define expectations for matching parameters.
If you don't care about parameters just say so (I called the method WhenCallingWithAnyArguments in my mocks) and pass dummy values (empty string, 0, nil, ...).
procedure TMyTest.ForgotMyPassword;
var
SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(TypeInfo(ISmsSender), SmsSender);
When(SmsSender.Send()).Returns(True);
TInterfaceMock.Create(TypeInfo(IUserRepository), UserRepository, Self);
When(UserRepository.Save()).ExpectsCount(qoEqualTo, 1);
StartExecution;
with TLoginController.Create(UserRepository, SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
Here When() and StartExecution may use some global threadvar context for proper execution.
My concern is that you can not just call SmsSender.Send() with no parameters...
Two possibilities:
- Make all parameters optional (may introduce issues);
- Force putting some parameters (code will inflate and be difficult to write).
How to resolve this?
]]>By setting a flag during the SmsSender.Send() fake execution, which may be retrieved by When()?
Could make sense... an idea to explore, I suspect.But then, when the instances are injected to TLoginController, they should behave as expected.
For instance, all the internal journaling should be reset before execution.Was it what you proposed?
Exactly
]]>interface.method will e.g. return a string or a boolean - how may When() indentify the original method?
By setting a flag during the SmsSender.Send() fake execution, which may be retrieved by When()?
Could make sense... an idea to explore, I suspect.
But then, when the instances are injected to TLoginController, they should behave as expected.
For instance, all the internal journaling should be reset before execution.
Was it what you proposed?
]]>How refactoring will break the code in your opinion?
You do not need to specify all parameters every time, and you can add methods to any interface without breaking the stubbing/mocking code.
Renaming a method or changing signature will cause the test to fail at runtime, not at compiletime. And that is for every test that uses a mock of the changed interface.
Using strings as identifier is one of the major weak points of certain mock frameworks, while others solve that problem by avoiding that.
I think even without generics (although they allow a much nicer fluent interface style to define expectations) this is possible (not perfect though)
procedure TMyTest.ForgotMyPassword;
var
SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(TypeInfo(ISmsSender), SmsSender);
When(SmsSender.Send()).Returns(True);
TInterfaceMock.Create(TypeInfo(IUserRepository), UserRepository, Self);
When(UserRepository.Save()).ExpectsCount(qoEqualTo, 1);
with TLoginController.Create(UserRepository, SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
The method call to the mock/stub interface which is done before calling When captures the method/instance and Returns and ExpectsCount apply the expectation to this method/instance.
This should work down to Delphi 6 for any function with the matching overloads for When, just not for procedures.
Edit: changed the order of the calls
]]>But by design, even if code may break at runtime, it will be during stub/mock definition (with an error about an unknown method name), so it won't be an issue for testing. Test will fail. But no false negative would occur. I suspect this is not an issue.
How refactoring will break the code in your opinion?
You do not need to specify all parameters every time, and you can add methods to any interface without breaking the stubbing/mocking code.