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 08: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.

blog comments powered by Disqus

My Book

A Pithy Quote for You

"Luck is what happens when preparation meets opportunity."    –  Seneca

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.