Boost logo

Boost Users :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2006-09-15 08:41:29


Scott Meyers wrote:
> David Abrahams wrote:
>> I'd much rather develop a library of mock objects for testing. Okay
>> a conforming mock stream may be a little work to write, but you
>> write it once and you're done.
>
> I take this to mean that you have not found it
> necessary/desirable/useful to create separate test and client
> interfaces. Okay.
>
> 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?

This situation should be rare in well-designed code. Either f requires a
BigHonkingHairyClass in order to work - by this I mean the precise semantics
of BHHC - and it has to be tested using a BHHC; you can't substitute a mock
that emulates a BHHC perfectly because it will be a BHHC itself.

Or, f doesn't really require a BHHC, and it should be rewritten in one of
the two ways above. This allows client A to pass a BHHC and client B to pass
something else. From the library design PoV, it doesn't matter whether
client B is a test suite or just another module.

It is true that in many projects, the lower layers aren't designed as a
proper library, since they don't have to serve arbitrary client code. In
such a case, having a test suite as a second client can indeed lead to
problems like the above. :-)

Another angle is that tests should test the behavior that is exercised by
the application. If the application uses f with a BHHC, the tests should
test f with a BHHC. Testing f with a mock can find some errors, but may
easily miss others. This can be substituted by defining a rigorous interface
for BHHCs and testing both f and BHHC against that interface, of course,
which gets us back to one of the two refactorings given above. (But the
f+actual BHHC test should still be part of the suite, IMO.)


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net