Amazon.com Widgets TVirtualInterface: A Truly Dynamic and Even Useful Example

TVirtualInterface: A Truly Dynamic and Even Useful Example

By Nick at June 30, 2012 17:25
Filed Under: Delphi, Software Development, Unit Testing

Introduction

This is the third article in a series about using TVirtualInterface.  The two previous articles are TVirtualInterface: Interfaces without an Implementing Class and TVirtualInterface: Next Steps.

Okay, enough with the not-all-that-useful examples.  I mean, the previous articles were illustrative, but not really “real-world useful”.

The true usefulness of TVirtualInterface occurs when you use it to create code where you have no idea what interface the user of your code is going to try to implement.  All the examples so far have shown only implementing classes where you do know which interface is being used.  The exception so far is the TReportingVirtualInterface example which reports information on any interface you pass to it.  Since we have proven that you can use TVirtualInterface to do something useful, let’s take it a step further.

A practical use of TVirtualInterface is to create a mocking library for unit testing.  I’ve mentioned numerous times the Delphi Mocks Framework by Vince Parrett of FinalBuilder fame.  Another excellent implementation of a mocking framework (as well as a bunch of other very innovative and interesting stuff) is by Stefan Glienke as part of his Delphi Sorcery framework.  Both of these use TVirtualInterface to provide a mock implementation for any interface (though the Delphi Sorcery code implements its own version of TVirtualInterface that works with Delphi XE – very cool).  Both, of course, allow you to pass them any interface, and they’ll happily mock your interface for unit testing purposes.  So why not do an example here of a very simple mocking object that you can actually use if you want?

ISimpleStub

A while back I wrote an article called The Vocabulary of Unit Testing.  In it I described the distinction between a stub and a mock.  I defined a “stub” as “a fake that has no effect on the passing or failing of the test, and that exists purely to allow the test to run.”  So, how about we build a universal stub – a class that can pretend to be any interface you want, and not do anything at all.  That can’t be that tough, can it?

Well, we already have a class that can implement an interface, but we need to find a way for that class to actually be the interface.  If you want a stub, the stub has to actually be the interface type you are trying to stub out, right?

First, since we always code against abstractions, let’s declare an interface:

  ISimpleStub<T> = interface
  ['{6AA7C2F0-E62F-497B-9A77-04D6F369A288}']
    function InterfaceToCall: T;
  end;

And then let’s implement it with a descendent of TVirtualInterfaceEx<T>:

  TSimpleStub<T: IInvokable> = class(TVirtualInterfaceEx<T>, ISimpleStub<T>)
  protected
    procedure DoInvokeImpl(Method: TRttiMethod;  const Args: TArray<TValue>; out Result: TValue); override;
  public
    function InterfaceToCall: T;
  end;

Because TSimpleStub<T> descends from TVirtualInterfaceEx<T>, it can implement any interface you pass to it.  It thus overrides DoInvokeImpl from  TVirtualInterfaceEx<T> as well as implementing InterfaceToCall from ISimpleStub<T>.

First, let’s look at DoInvokeImpl:

procedure TSimpleStub<T>.DoInvokeImpl(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
begin
  // Since this is a pure stub, don't do anything!
end;

Not much to see here  – it doesn’t do anything.  And for a stub, that is fine.  That’s exactly what stubs are supposed to do – nothing.  We don’t care what happens when the methods get called, you just need to actually be able to call them.

That’s where the InterfaceToCall function comes in.  The class knows about the type of interface being stubbed because we are passing that type in as a parameterized type.  The class itself knows how to implement that interface.  There has to be a way to get an actual reference to that implemented interface, right?  This is where the InterfaceToCall method comes in:

function TSimpleStub<T>.InterfaceToCall: T;
var
  pInfo : PTypeInfo;
begin
  pInfo := TypeInfo(T);
  if QueryInterface(GetTypeData(pInfo).Guid, Result) <> 0 then
  begin
    raise Exception.CreateFmt('Sorry, TSimpleStub<T> is unable to cast %s to its interface ', [string(pInfo.Name)]);
  end;
end;

Since TSimpleStub<T> knows the type that T is, you can call QueryInterface on the type information about T itself to get a reference to the interface in question.  And of course, once you have that, you can pass that reference anywhere you need to stub out the interface – normally as part of unit testing.

So now, you can safely call methods on the stubbed interface.  For instance, given this interface:

IActuallyUseful = interface(IInvokable)
  ['{16F01BF0-961F-4461-AEBE-B1ACB8D3F0F4}']
  procedure SayHello;
  function ReverseString(aString: string): string;
  function Multiply(x, y: integer): integer;
end;

Writeln('Implementing a TSimpleStub');
SimpleStub := TSimpleStub<IActuallyUseful>.Create;
WriteLn('Nothing should appear between this and the next statement');
SimpleStub.InterfaceToCall.SayHello;
SimpleStub.InterfaceToCall.Multiply(4, 4);
SimpleStub.InterfaceToCall.ReverseString('blah');
WriteLn('Nothing should appear between this and the above statement');
WriteLn;

Nothing happens when you call the interface methods, but that’s by design:  stubs should do nothing.  What you can do is call them as part of your unit testing:

begin
  ...
  MyClassUnderTest := TSprocketThatTakesAnIWhatever.Create(SimpleStub.InterfaceToCall)
  ...
end;

TSimpleMock

Okay, so there’s a useful, dynamic way to use TVirtualInterfaceTSimpleStub<T> will work great for a stub that you expect absolutely nothing from.  But sometimes you need a fake interface that does something more than just existing, and when that is the case, you are creating a mock.  In my unit testing definitions article, I defined a mock as “a fake that keeps track of the behavior of the Class Under Test and passes or fails the test based on that behavior.”  Thus, a mock needs to do more than exist like a stub –  it needs to behave in a way that you can define.   So how about we take TSimpleMock<T> and make it do a basic mocking function – responding in a specific way to a specific input.

One of the most common things that a mock interface does is to respond with “this” when passed “that”.  How about we create a simple mock class that lets you define a specific response to a method call?

First, of course, is an interface to code against:

 

  ISimpleMock<T> = interface(ISimpleStub<T>)
  ['{9619542B-A53B-4C0C-B915-45ED140E6479}']
    procedure AddExpectation(aCallName: string; aReturnValue: TValue);
  end;

The interface augments (“inherits from” is not quite right with interfaces) ISimpleStub<T> and adds the AddExpectation method.  This is the method that we’ll use to tell the mock out to respond when and interface method gets called. 

Here’s the implementing class:

  TSimpleMock<T: IInvokable> = class(TSimpleStub<T>, ISimpleMock<T>)
  private
    FActions: TDictionary<string, TValue>;
  protected
    procedure DoInvokeImpl(Method: TRttiMethod;  const Args: TArray<TValue>; out Result: TValue); override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AddExpectation(aCallName: string; aReturnValue: TValue);
  end;

The first thing to notice is that TSimpleMock<T> inherits  from TSimpleStub<T>, thus enabling it to “be” any interface it wants as our stub was. And of course it also implements the  AddExpection method.  It takes as parameters the name of the method on the interface that you can call, as well as a return value for when that method gets called.  In this way you can define the behavior of the mock class however you want.

This very simple mocking example assumes that you are going to be mocking only function calls as methods on an interface. Within the confines of our simple example, it doesn’t make sense to mock procedures – they basically don’t do anything as far as the simple example is concerned.  Real mock frameworks are able to keep track of whether a procedure is called, how many times it does get called, and other things associated with procedures.  This simple example also doesn’t care what parameters you pass in, it will merely return a value whenever the named method is called.   Remember, this is a simple – but useful in specific situations -- example.  Winking smile 

The implementation of TSimpleMock<T> is pretty, well, simple.  Internally, it uses a TDictionary<TKey, TValue> to keep track of the method calls and the resulting responses that are added via the AddExpectation call.  Here is the implementation of AddExpectation :

procedure TSimpleMock<T>.AddExpectation(const aCallName: string; aReturnValue: TValue);
begin
  FActions.Add(aCallName, aReturnValue);
end;

When you add an expectation, the class keeps track of it.  When you then call that method on the interface, it is able to retrieve the expected return value from the dictionary and return it:

procedure TSimpleMock<T>.DoInvokeImpl(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
begin
  Result := FActions[Method.Name];
end;

(The obvious shortcoming here is no error handling – you’ll get an exception if you try to call a method on the interface that doesn’t  have an expectation entry.  Another shortcoming is that the parameters passed mean nothing – a real mocking framework would be able to provide specific responses for specific parameter inputs.    I’ll leave correcting this problem as an exercise to the reader.  Smile )

So now, when we exercise this class, it will actually return stuff that you tell it to:

This code:

WriteLn('IActuallyUseful with ISimpleMock');
SimpleMock := TSimpleMock<IActuallyUseful>.Create;
SimpleMock.AddExpectation('Multiply', 99);
SimpleMock.AddExpectation('ReverseString', 'This is actually working');
WriteLn(SimpleMock.InterfaceToCall.Multiply(6, 7));
WriteLn(SimpleMock.InterfaceToCall.ReverseString('This does not matter'));
WriteLn;

has the following output:

image

Note that the responses are not what you think they would be based on the parameters (you think that 6 times 7 would return 42…), but what you told them to be in the AddExpectation call.

Now, you can use ISimpleMock<T> to provide specific feedback for a given method call.  Maybe you have an interface method which returns a Boolean value that you want to test. You can use ISimpleMock<IBooleanMethod> to test what happens when the method returns True as well as when that method returns False

Conclusion

Okay, so there you have it:  A useful implementation of TVirtualInterface.  Though the above examples are really simple, they can actually be used in real world testing – particularly the ISimpleStub<T> implementation. Stubbing is common in unit testing, and even though it is a very basic implementation, it can be used to stub out any interface.

None of this is useful if you know what interface you need and how you are going to implement it.  But there are cases when you don’t know what interface you will need for a particular problem, and you need to be able to flex to whatever interface the situation calls for.  Mocking and stubbing are perfect examples.  That’s a powerful and useful thing to be able to do.  Hopefully this little series has helped you see that.

Comments (10) -

6/30/2012 7:04:12 PM #

Jason Southwell

Just wanted to mention that the latest DuckDuckDelphi uses this internally to ducktype to a specified interface.

For example...

IAdder = interface(IInterface)
  function Add(a,b : integer) : integer;
end;

TMyObject = class(Tobject)
  function Add(a,b : integer) : integer;
end;

var
  obj : TMyObject;
  intf : IAdder;
begin
  obj := TMyObject.Create;
  intf := obj.duck.asA<IAdder> as IAdder;
  result := intf.add(1,2);
end;

Jason Southwell United States |

6/30/2012 9:29:51 PM #

nick

Jason -- Hey, very cool  DuckDuckDelphi is a cool thing, and I should have known it used TVirtualInterface.  

Here's a link to DuckDuckDelphi:

http://code.google.com/p/duckduckdelphi/

nick United States |

7/1/2012 4:12:32 AM #

Jeroen Pluimers

Thanks for this great series of articles.

Features like generics, anonymous methods and TValue paved the way for a whole new set of libraries.

Things like mock, duck, etc would have been either impossible or very hard to do (just look at how Delphi 6 added SOAP support, and how SOAP and REST can be done now).

Kudos to the people making those libraries, and thank you for showing insight on how some of the internals work.

--jeroen

Jeroen Pluimers Netherlands |

7/1/2012 10:50:45 AM #

Arnaud Bouchez

Thanks for the subject, NIck.

But if I do agree with your general definition of stub/mock, I do not agree with your implementation, as you detail it in this article.
Take a look at this reference article: martinfowler.com/articles/mocksArentStubs.html
You present stubs are "void implementations", but this is not what they should be. Stubs can return some data, even make some process (yes they can!!!!) but they should not affect the fact that the test will pass or fail. In short: they will let always the test pass, whereas mocks can let the test fail, and testing shall ensure that it is the case.
Even if you do not make the confusion yourself, you may confuse some readers by such writing!
Please try again... this example is not yet useful, and can be misleading... ;)

@Jeroen You can do wonders without generics, even with good old Delphi 6. "Regular RTTI" is enough to make some nice RESTful interface based services with Delphi 6 or 7, and still be compatible with newer versions. The TypeInfo(aClass) and all the supplied RTTI is very powerful, and you can create a lot of features without using generics (and their overload and bugs).
See our Open Source mORMot framework - blog.synopse.info/.../Interface-based-services-implementation-details
Our  TInterfacedObjectFake class has some mandatory features against TVirtualInterface, which sounds like another half-finished feature of Delphi:
- It works from Delphi 6 up to XE2, even with Starter Edition (only 32 bit Windows by now);
- It does allow to pass VAR parameters, and OUT parameters;
- It shares the VMT for all instances, and has near to zero overhead (whereas TVirtualInterface has a huge amount of plumbing and marshalling).
Take a look at the sources, and you'll find out what I mean.

I'll soon add some stub/mock features to mORMot, working also with Delphi 6, and allowing VAR/OUT parameters and such.

Arnaud Bouchez France |

7/1/2012 2:33:42 PM #

Stefan Glienke

Why did I see that coming? ;)

Stefan Glienke Germany |

7/1/2012 4:50:15 PM #

Arnaud Bouchez

Because we already met!
Smile

Arnaud Bouchez France |

7/1/2012 6:51:09 PM #

Stefan Glienke

Mind refactoring your code from SQLite3Commons.pas (TInterfacedObjectFake) to something that has no dependencies that are irrelavant for the things you have commented on recently?

You always telling us that these things have been possible for over a decade now (which I don't argue about, since I know you are right) but looking at said unit reveals that it's nothing one can simply use to achieve these things (at least not like most of the people that have no clue about the internals or even assembler handcrafting).

So as long as there is no easy to use class that provides the features that TVirtualInterface and the other stuff in Rtti.pas do most people will stick to that even if you and others claim that there is unnecessary much overhead and/or performance impact. Provide us with something better and equally easy to use (personally I don't care if it runs on last century Delphi, but some may do) and we are talking Smile

Stefan Glienke Germany |

7/3/2012 9:50:18 AM #

Arnaud Bouchez

I already answered to those points in your blog.

Arnaud Bouchez France |

7/2/2012 3:48:06 AM #

dangi

@Jeroen, @Arnaud, @Stefan If you are looking for a TVirtualInterface-like class for older versions of Delphi, there is one in the PascalMock ( (1) mock framework for Delphi before the new RTTI/Generics) source: the TPascalMockRIO (2) class allow easy implementation by overriding CallMethod(). See TAutoMockIntf (3) for an example.
PascalMock is a bit dated now and newer solutions have advantages, but it can still be useful, and has no dependencies.

1) http://sourceforge.net/projects/pascalmock/
2) pascalmock.cvs.sourceforge.net/.../...lMockRio.pas
3) pascalmock.cvs.sourceforge.net/.../...MockIntf.pas

dangi France |

7/3/2012 9:54:51 AM #

Arnaud Bouchez

Thanks for the link!

Arnaud Bouchez France |

Pingbacks and trackbacks (1)+

Comments are closed

A Pithy Quote for You

"If we seek merely swollen, slothful ease and ignoble peace, if we shrink from the hard contests where men must win at the hazard of their lives and risk all that they hold dear, then bolder and stronger peoples will pass us by, and win for themselves the domination of the world."    –  Theodore Roosevelt

Amazon Gift Cards

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.

Month List