views:

261

answers:

3

I've never developed using Test Driven Development, and I've never used Mock Objects for unit testing. I've always unit tested simple objects that don't incorporate other aspects of the application, and then moved on to less simple objects that only reference objects that have already been unit tested. This tends to progress until the final "unit" test is a component test.

What design techniques are used to make the replacing of internal classes with Mock Objects as easy as possible?

For example, in my code, I would include the header file for myDataClass within myWorkerClass. myDataClass is constructed by myWorkerClass, and its lifetime is tied to myWorkerClass. How can you set it up so that it would include a mock myDataClass when the include is hard-wired?

A: 

One way would be to not hard-wire your classes like that.

Using your example:

myDataClass would be a pure virtual class. This would have at least 2 implementations, the 'real' one and the mock.

Your test code could inject a mock instance by having 2 constructors, one that takes a 'myDataClass' and one that doesn't. See the code below for an example.

class myWorkerClass {
public:
    myWorkerClass(myDataClass * dc) : m_dc(dc) {}
    myWorkerClass() : m_dc(new MyRealDataClass()) { }
    ~myWorkerClass { delete m_dc; }

private:
    myDataClass *m_dc;
}

Now, you can provide any implementation of the myDataClass to the myWorkerClass you want. If you don't provide an implementation, then your code falls back on the 'real' implementation.

Another technique would be to use the Factory pattern to instantiate your objects. Your test code could set some flag on the factory that creates instances of myDataClass and have it produce a mock object instead of the real one. I prefer the first technique as to me it's a little easier to use (plus I don't have to maintain a factory class for everything I want to test)

Glen
You bind myWorkerClass to MyRealDataClass realization. If MyRealDataClass is impossible to instantiate in unit-test conditions, you won't be able to compile this example.
Basilevs
@Basilevs, Under test conditions MyRealDataClass will never be instantiated, and with my technique the users of myWorkerClass aren't exposed to the implementation details of myWorkerClass unless they need to be.
Glen
By instantiation I mean compiler emitting the code of MyRealDataClass functions. Hiding implementation details is a good point, though.
Basilevs
+3  A: 
Basilevs
+2  A: 

You could look to adapt your code to follow an (Abstract) Factory Design pattern, whereby a different factory could be used in a unit test environment that would create your mock objects.

Alan