On Thursday, September 14, 2006 at 17:21:17 (-0700) Scott Meyers writes:
... My understanding is that the ability to drop in mock objects requires programming to an interface that can be either a "real" object or a mock object, which in turn suggests using either a template parameter or a base class. Suppose, for example, you have this:
class BigHonkinHairyClass { ... // expensive to construct };
and you want to implement some function f that takes a BigHonkinHairyClass as a parameter. The straightforward declaration would be
void f(BigHonkinHairyClass& bhhc); // maybe const, doesn't matter
But now it's hard to drop in a mock. So I assume you'd modify the interface to be either
template<typename T> void f(T& bhhc); // T must more or less model // BigHonkinHairyClass
or this:
class BigHonkinHairyBase { ... // interface to program against -- }; // uses virtuals
class BigHonkinHairyClass: public BigHonkinHairyBase { ... };
class MockHonkinHairyClass: public BigHonkinHairyBase { ... };
void f(BigHonkinHairyBase& bhhc);
Is that correct? In other words, you'd come up with an interface that let clients do what they wanted but that was also mock-friendly for testing purposes? That is, you'd take testability into account when designing your client interface?
That all depends: I think you reach a point where intrusive testing is rather costly (construction costs, etc.) and external testing (Tcl-based expect scripts, perhaps) is a better approach. This is essentially the approach I have taken over the years. At some point, the unit tests become hopelessly complex, Mock objects begin to weigh development down (if you change the interface, you have to change your mock objects) and a transition is made to higher-level integrated testing. However, I think your points above are essentially correct. Bill