8

Let's assume you have a very well designed Delphi project, which respects the dependency injection and some other good practices.

Now let's assume you need to mock a class defined as:

TMyClass = class
public
  procedure Method1;
  procedure Method2
end;  

Method1 and Method2 are not virtual. What do you do in this case? To mock an object we need to inherit it and override every method you want to mock, but it is not possible in this case because they are not virtual. Should I change the source code to add virtual on every method I need to mock? Is not it bad?

Edit

I was thinking about creating a compiler directive to make all fields in the class to be virtual, is it a good ideia? Only my test suite is going to set the compiler directive.

EDIT2*

Embarcadero should provide an easy way of changing a method pointer of a class to another method point, without the need for virtual.

Rafael Colucci
  • 6,018
  • 4
  • 52
  • 121
  • 1
    Your edit is a completely separate issue. Please ask it in a new question. But before you do, please see [Accessing private fields](http://stackoverflow.com/questions/5123395/accessing-private-fields) and [How can I test private methods with DUnit?](http://stackoverflow.com/questions/422379/how-can-i-test-private-methods-with-dunit) – Rob Kennedy May 02 '11 at 21:14
  • Sorry, It was supposed to be `virtual` and not `public`. – Rafael Colucci May 02 '11 at 21:18
  • 2
    @Rafael, regarding your **EDIT2** this is exactly what `virtual` enables why do you want to confuse 15 years of using virtual to replace it with something, and I'm sure there is a regex to replace all non virtual declaration with `virtual; {temp}` as well as a regex to replace the `virtual {temp}` back to just a `;`. – Johan May 02 '11 at 22:54
  • You ridicule its static way of doing things – Johan May 03 '11 at 16:56
  • @Rafael, english play on words: to mock = to ridicule, make fun of; opposite of virtual = static (sort of); method= way of doing things {I know... lame} – Johan May 03 '11 at 21:51
  • @Johan, lol .. now I get it. I have learn something new! – Rafael Colucci May 04 '11 at 12:13

3 Answers3

12

Make the methods virtual so you can mock them. (They don't need to be abstract.)

If you cannot do that, then wrap the class with another class. Make the wrapper's methods virtual, and in the default implementation, just forward call calls to the original class. Wherever your program uses the original class, replace it with the wrapper. Now, mock the wrapper.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Well .. this is kind a complex way. I like the idea of wrapping the class but changing all the source code is going to be very hard to do. – Rafael Colucci May 02 '11 at 21:00
  • It doesn't have to be hard at all. You can let the IDE tell you exactly what needs to change. Use the "find references" command (in the refactoring menu, I think) to tell you where the original class is used. Or rename the original class and use the list of compilation errors to help you find all the code that needs changing. – Rob Kennedy May 02 '11 at 21:02
  • 1
    My project has more than 200 classes, it a 10 year old project. Trust me: changing the source code as you told me is not possible. Also, this can be easy if I want to mock only 1 class, but how about 10? ou maybe 20? – Rafael Colucci May 02 '11 at 21:06
  • The "find and replace" command works just as well on 20 files as it does on 200. – Rob Kennedy May 02 '11 at 21:10
  • Yeah, but the effort to make all changes are not the same. – Rafael Colucci May 02 '11 at 21:13
  • I don't think it's really that much more work. If the IDE can't make the changes for you, then a simple `sed` script should be able to make all your changes in a few minutes, and if it doesn't work, restore from source control and try again. But if you still don't like the effort of wrapping the classes, then you can go with my first suggestion instead and just make the methods virtual. That requires changing just one file. – Rob Kennedy May 02 '11 at 21:19
  • Yeah. I guess I will go for making them virtual, but i really think embarcadero should take care of it soon. Btw i have seem some mock frameworks around. How do they work? – Rafael Colucci May 02 '11 at 21:23
  • In my experience Mocking requires either Interfaces or Virtual Methods. – Robert Love May 03 '11 at 13:47
  • Personaly I prefer implementing an interface over inheriting or wrapping as Nick Hodges suggested in his solution. Inheriting (and wrapping) does not allow "disabling" functionality that might influence the code being tested. Implementing a complete class according to an interface, does. – Brave Cobra Jan 02 '12 at 17:03
  • @Brave, you can disable any functionality you want. Simply override a method and do nothing in it. It's the same as implementing an interface method and doing nothing. – Rob Kennedy Jan 03 '12 at 14:50
  • @RobKennedy Well you can't with (strict) private functions that do calls to ie. singletons that you want to rule out of the equation! Interfaces mocking doesn't pose that problem. Inheritance works in most case but not all. Interface mocking works all the time :) – Brave Cobra Jan 07 '12 at 19:12
  • I don't understand, @Brave. So, the object we want to mock has a private method, and we don't want that private method to do anything, right? The code under test obviously won't be calling that method directly (since it's private), so we don't need to disable it directly. Find the *public* methods that would call it, override them in the mock descendant, and don't call the private method. Likewise when mock-implementing the interface: Find the method, and don't do anything. I don't see how the singleton in this scenario matters at all. – Rob Kennedy Jan 08 '12 at 02:02
6

To mock an object we need to inherit it, but it is not possible in this case.

I'd recommend that every class that you say "I need to mock this" should end up being based on an interface.

In other words, if you have methods that need to be mocked, they should be put into an interface, and then the class to be mocked implements that interface. Then, you create the mock by implementing the same interface in the mock object.

The alternative is to use a Mocking library. You can look at these SO question:

What is your favorite Delphi mocking library?

and this framework includes mocking objects as well:

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

Mocking objects should also encourage the proper use of dependency injection in your code.

Community
  • 1
  • 1
Nick Hodges
  • 16,902
  • 11
  • 68
  • 130
  • 1
    i agree that it should use an interface, but not using the Interface keyword, at least if you need to avoid reference counting. The automatic requirement to use reference counting with delphi's Interface keyword makes it a key drawback. Just be aware. – Warren P May 03 '11 at 03:02
  • 2
    @Warren: There is no "requirement" to use refcounting with Delphi's interface keyword. You can simply return -1 in the \_AddRef and \_Release methods of the interface to disable the refcounting mechanism. Just be aware that you are introducing ambiguity when you also have interfaced objects that _do_ make use of refcounting for life time management. – Marjan Venema May 03 '11 at 06:23
  • 1
    @Marjan, the return values of those functions have *absolutely no effect* on reference counting. You disable reference counting by implementing those functions and simply *not counting references*. But no matter what the functions return, and no matter what else you do or don't do in those functions, they still *always* get called, so you still need to manage references, even if you don't count them. If you manually free an object while there are still interface references to it anywhere, your program will eventually crash. – Rob Kennedy May 03 '11 at 14:02
  • Marjan: I consider such ambiguity is more accurately called "lying". Things that provide an IUnknown interface, but which can randomly get freed, without reference counting being referred to, are a whole world of hurt. TANSTAAFL. I don't believe in lying to people. If you implement IUnknown, and you just free the object at some point before the application terminates, you will run a huge risk of problems. Not just ambiguity. Crashes. – Warren P May 03 '11 at 18:28
  • @Rob: Yes, you are right. I misinterpreted @Warren's statement as interface always carrying the drawback of refcounted *life time managment*. The life time managment can be avoided, the compiler injected calls to \_AddRef and \_Release cannot... – Marjan Venema May 04 '11 at 06:04
  • @Warren: I understand and agree with your point. However sometimes you need interfaces to decouple things nicely, but do not want to introduce ref counted life time management into an otherwise "manually managed" code base. In private projects I tend to use class names starting with Ti (i for interface) and Tnr (nr for non-ref-counted) or some such so the name always tells you whether the class's life time is ref count or manually managed. – Marjan Venema May 04 '11 at 06:10
  • @Marjan: Very good idea. If you wanted to do something like that, I think your naming convention is a very high-quality way of doing it. Then you have to make sure the devs who work on your codebase are aware of your conventions, and things should be fine. – Warren P May 04 '11 at 14:13
  • @WarrenP: If you want to "disable" the ref counting then, just call _add and _release once each. That should keep the reference at 1 and should enable you to free whenever you want. – Brave Cobra Jan 02 '12 at 17:05
5

You should not only make the methods virtual, you should declare a pure virtual base class, and make the other classes use only the pure virtual base class name. Now you can use what we call the "Liskov substitution principle", and you can make as many concrete subtypes of the abstract base class as you need. Since the abstract base class works just like an Interface works in delphi, minus the reference counting part, you get the best of both worlds. You can really keep your app code simple, and reduce bad coupling this way, plus you get unit testable "composite objects" that you put together yourself.

// in UnitBase.pas
TMyClassBase = class
public
  procedure Method1; virtual; abstract;
  procedure Method2; virtual; abstract;
end; 

// in UnitReal.pas
TMyClassReal = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

// in UnitMock.pas 
TMyClassMock = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

In the place that uses "TMyClass", change it to use TMyClassbase:

TMyOtherClass = class(TMyOtherClassBase)
private
  FMyThing:TMyClassbase;
public
  property MyThing:TMyClassBase read FMyThing write FMyThing;
end;

By connecting TMyOtherclass at runtime you can decide whether to use the real or mock class:

// in my realapp.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassReal.Create;  // real object

// in my unittest.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassMock.Create;  // mock object

(Don't forget to make a way to free MyOtherClassObj.MyThing later, or you'll have a leak)

Rafael Colucci
  • 6,018
  • 4
  • 52
  • 121
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 2
    What advantage is there to making an abstract base class? You mention having multiple subtypes, but the application already works with *no* subtypes, so why bother with the extra effort of introducing more inheritance? – Rob Kennedy May 03 '11 at 04:18
  • @Warren, Thanks, but i am wondering what is the benefit from having such thing. – Rafael Colucci May 03 '11 at 12:57
  • The benefit is that now you can have UnitOtherClass.pas depend only on AbstractBaseClasses.pas, and not on the specific implementation that you wrote. Imagine in the future, you truly want to remove the one class, and use the other. But you have uses-clause references to everything everywhere. You can't quickly remove that class, without editing all the files that drag in that dependency. – Warren P May 03 '11 at 13:52
  • A second benefit exists for unit testing. Imagine the abstract base class manages a database connection. Now you can unit test without a database connection, or internet connectivity, or whatever complex thing the class abstracts away. It really is abstract, and so it can be GONE. This is not necessary in 100% of cases, but where it enables unit testing, it also usually enables a tonne of other useful things in the future, like database-back-end-plugins etc etc. – Warren P May 03 '11 at 14:59
  • The idea is nice, but it is not possible to me implemented write now. But I will keep it for future new apps. Thanks for sharing. – Rafael Colucci May 03 '11 at 15:58
  • Great attitude Rafael. And my tip is not even appropriate to 100% of places. Use the YAGNI principle, and when you absolutely need this, do it. Otherwise, don't. Abstraction and complexity for its own sake is a hindrance. But if it really helps you, and you use it, you'll thank yourself. – Warren P May 03 '11 at 18:27
  • What is the advantage of this over using an _actual_ interface? Your abstract base class could, as far as I can see, be substituted with an interface. That way, you remove a layer of dependecy? – Undreren Feb 19 '16 at 10:06
  • In Delphi where you don't want to implement a reference counted semantic, instead you want manual allocation and deallocation of objects and precisely described object lifetimes, a pure virtual base class is a cleaner solution. It is possible to remove reference counting from an Interface implementation but that is ugly and should not be done. – Warren P Feb 25 '16 at 23:46