tags:

views:

197

answers:

4

Suppose I have a class A which depends on 3 other classes X, Y and Z, either A uses these through a reference or a pointer or say A is templated to be instantiated with X, Y and Z doesn't matter, the key is that in order to test A, I need to have X, Y and Z.

So I need to have fakes for A, B and C. Suppose I write them. Now, how do I swap real and fake objects easily? I can see that this works very easily in the case of templates. In order to make it work when A depends on X, Y and Z through a reference or a pointer, I would need to have a base class say X_Interface from which I can inherit X_Real and X_Fake.

So basically, I would end up in having 3 times the number of classes for every class that would need to have a fake.

I am most likely missing something. There has to be a simpler way to do this. Having a base class X_Interface is also quite expensive as I will be using more space and making virtual calls. I guess I could use CRTP as I know whether its a X_Real or X_Fake at compile time but still there must be a better way.

+1  A: 

I think you are looking for a dependency injection framework. See the past SO questions on this.

Matthew Flaschen
A: 

Unfortunately, there isn't much option in strongly, compile-time typed languages. That's actually OK, because good architecture practice also pushes you towards programming to interfaces, rather than implementations. In order to minimize dependencies between modules/classes, you should have at least, e.g. X_Interface and X_Real. In this case, good design and good testability go hand-in-hand. I suspect that many TDD'ers would point out that that's exactly the point.

Barry Wark
Is it necessarily good design to double the number of classes in your application?
jalf
Only if a class is an architectural boundary between responsibilities you should define an interface. Only then is it beneficial to design such a 'contract' as the implementations of the responsibilities can then be exchanged freely. Within a responsibility there is hardly a reason to be able to do this. In testing context you could just extend the original class, the original class IS the contract/interface. But I do not think this is necessary (see my answer).
NomeN
+2  A: 

First make sure that the objects you depend on (X, Y & Z) are passed in at the constructor, this way you can easily pass in 'fakes' when you are testing. (I really hope you are using a unit test framework, like CUnit)

Now when you are writing the test, all you need to do is make up 'fakes' for the objects the class under test depends on. Often you can just pass in 'null', but if you really need to do something with that 'fake' you can simply instantiate it (you made sure all its dependencies are passed in at the constructor too, right? right!).

Or in an extreme case you might extend the class that is depended upon and reimplement some key methods to suit your test.

So now in most cases you don't need a 'fake', sometimes you simply instantiate a real 'fake', and in rare cases you have an extra class that resides only in your test code.

Look at this video for a much better explanation.

There are more on this topic from GoogleTechTalks, but you'll manage from here.

NomeN
+2  A: 

Although you often hear that a unit test should cover only one class, depending on the complexity of your classes, you may not have to do that and can test all 3 at the same time.

You always have to consider the return on investment. How much will you gain by testing the components separately vs how much effort you have to put into it. A few things to consider:

  • If a bug is discovered during automated test of all 3 classes together, will it still be easy to debug it? Is so, consider testing all 3 at the same time.

  • Will it be a common thing to replace one of the 3 classes with another class (which implements the same interface)? If so, testing the classes separately may make more sense.

  • Are the three classes pretty much designed to only work together? Then test them at the same time.

Also consider that TDD is not the same as Unit Testing. The tests in TDD don't have to be pure unit tests. As long as you can run them in an automated way the tests will do a lot of good. Where I work our test suite is a mix of pure unit tests and command line tools which are executed and verified for an expected return value.

Final note: in the great majority of cases the performance hit from having a pure interface base class won't matter much.

Martin
Testing multiple classes together does not help understandability. If I like to add a test case to one of those classes, where would I start? I probably won't find the 3-in-1 test, because I would be looking for the simple test class with the same name as the class under test. Probably my conclusion would be that there are no tests for the class, unless I happen to stumble upon it. Just save your colleagues the confusion and test each class on it's own. Only then consider *also* testing whole architectural modules on their own, if appropriate.
NomeN