Friends vs. Dependency Injections


I recently came across an interresting post on Chris’s Wiki. In short, Chris prefers not to use dependency injection for tests, but rather monkey-patch. The reason for doing this is that he “would rather have clean code and ugly tests than dirty code and cleaner tests”, which makes sense to me.

Spending most of my time in statically typed languages, monkey patching is a luxury (or should I say long rope) we don’t have, but it got me thinking whether we could do something similar in C++. Usually, people will tell you not to make your test-class (T) a friend of the class being exercised (E), since you will often end up testing for state instead of behaviour. But what if we make T a friend of E, and use that friendship only to sneakily substitute parts of E? For instance to swap out a real class it depends on (D) with a stub (DStub) providing synthetic data.

If E in production always uses the same type of D, it can instantiate D in its constructor, and we won’t have to inject an object of this type. In this case, using dependency injection would reduce readability just to support testing. If we let E set up its own D, the test can swap it out after E::E() has done its job, and the production code will have no traces of test-specific code. There are a few issues though:

If E stores the D object by pointer, we might need to manually delete the D it is pointing to before setting it to point to a DStub. (In production E would usually do this in its destructor.)

If E stores the D object by value, when we try to assign to it, it will use D’s copy assignment operator, not the one in DStub, and we will experience slicing. We of course also depend on D being copyable in the first place, but this requirement is not introduced by our test, it goes for the production code as well.

The last option, E storing the D object by reference, is only possible if we are already using dependency injection, or if something seriously weird is going on. You might want to think about why.)

Finally, and maybe most important of all, we require that all the methods in D that we want to stub are virtual.

So in conclusion, you probably shouldn’t monkey around, not even with good friends.

Appendix A, Answers to Exercises:

Why can’t we use references without dependency injection? Have a look at the following code:

struct D {};

struct E {
    D& d;
};

int main() {
    E e;
}

If you try to compile this, your compiler will complain about uninitialized reference members. A reference can never refer to “nothing” (unlike a pointer to null), and must be initialized with some object. This has to be done in the initializer list. When the body of the constructor is reached, it is already too late, as all members are initialized at this point.

How about this constructor for E then? E() : d(D()) {}; This won’t work, the object created will be a temporary, and references cannot refer to a temporary. This is one of the things that make them safer than pointers.

The only way to make this work would be to have a constructor that looks like this: E() : d(*(new D())) {};, and if it does, you have bigger issues than testability!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: