For another easier pattern, like the one in the Mockito home page:
TInterfaceMock.Create(TypeInfo(ICalculator),ICalc,self). ExpectsCount('Multiply',qoEqualTo,1). ExpectsCount('Add',[10,20],qoEqualTo,1); ICalc.Add(10,20); ICalc.Multiply(10,30)
If you want to follow the "test spy" pattern, you can use:
Mock := TInterfaceMockSpy.Create(TypeInfo(ICalculator),ICalc,self); ICalc.Add(10,20); ICalc.Multiply(10,30) Mock.Verify('Add'); Mock.Verify('Multiply',[10,30]);
If you compare with existing mocking frameworks, even in other languages / platforms like the two above, you will find out that the features included in mORMot are quite complete:
- Stubbing of any method, returning default values for results;
- Definition of the stubbed behavior via a simple fluent interface, with
TInterfaceStub.Returns()
, including easy definition of returned results values, for the whole method or following parameters/arguments matchers; - Handle methods with
var, out
or function result returned values - i.e. not only the function result (as other Delphi implementations does, due to a limitation of theTVirtualInterface
standard implementation, on which mORMot does not rely), but all outgoing values, as an array of values; - Stubbed methods can use delegates or event callbacks with
TInterfaceStub.Executes()
rule definitions, for the whole method or following parameters/arguments matchers, to run a more complex process; - Stubbed methods can also raise exceptions with
TInterfaceStub.Raises()
rule definitions, for the whole method or following parameters/arguments matchers, if this is the behavior to be tested; - Clear distinction between
mocks and stubs, with two dedicated classes, named
TInterfaceStub
andTInterfaceMock
; - Mocks are directly linked to mORMot's unitary tests / test-driven classes;
- Mocked methods can trigger test case failure with
TInterfaceMock.Fails()
definitions, for the whole method or following parameters/arguments matchers; - Mocking via "expect-run-verify" or "run-verify" (aka "test spy") patterns, on choice, depending on your testing expectations;
- Mocking validation against number of execution of a method, or a method
with arguments/parameters matchers, or the global execution trace - in this
case, pass count can be compared with operators like
< <= = <> > >=
and not only the classic exact-number-of-times and at-least-once verification; - Most common parameters and results definitions can be defined as simple
array of const
in the Delphi code, or by supplying JSON arrays (needed e.g. for more complex structures likerecord
values); - Execution trace retrieval in easy to read or write text format (and not via
complex "fluent" interface e.g. with
When
clauses); - Auto-release of the
TInterfaceStub TInterfaceMock TInterfaceMockSpy
generator instance, when the interface is no longer required, to minimize the code to type, and avoid potential memory leaks; - Works from Delphi 6 up to XE3 - since no use of syntax sugar like generics,
nor the
RTTI.pas
features; - Very good performance (the faster Delphi mocking framework, for sure), due
to very low overhead and its reuse of mORMot's low-level
interface-based services kernel using JSON serialization, which does not rely
on the slow and limited
TVirtualInterface
.
This article is part of a list of mocking/stubbing range of information:
- Interfaces in practice: dependency injection, stubs and mocks
- Stubs and Mocks for Delphi with mORMot;
- Advanced mocks and stubs;
Feedback is welcome on our forum, just as usual.