I hate a bit to mention but most of the time you don't need a full blown mock object libray. Often a more or less quick and dirty approach suffices if you do the right thing. In such cases I don't care too much about correct access restrictions or hiding variables behind methods. Tests usally lie in the lower areas of your project tree and nobody should try to re-use a test object in production code. So a more pragmatic approach won't hurt your project. But if you prefer you can of course do it the clean way.
The following sections contain some pattern I already used in my tests. They are kept simple but they certainly can be extended to cover similar real world scenarios.
The following example tracks the invocations to a reader object. The caller is expected to invoke each of the reader methods exactly once in this order:
This is done by incrementing a counter and assigning the current value to one variable for each method. After the test has run the values of all variables are checked.
class ReaderInterface
{
public:
virtual void open() = 0;
virtual void read() = 0;
virtual void close() = 0;
};
class ReaderMock : public ReaderInterface
{
public:
unsigned counter;
unsigned open_counter;
unsigned read_counter;
unsigned close_counter;
ReaderMock()
{
counter = 0;
open_counter = 0;
read_counter = 0;
close_counter = 0;
}
virtual void open()
{
open_counter = ++counter;
}
virtual void read()
{
read_counter = ++counter;
}
virtual void close()
{
close_counter = ++counter;
}
};
////////////////////////////////////////////
// The test within your testing framework
ReaderMock reader;
myMethodUnderTest(&reader);
assert(reader.counter == 3);
assert(reader.open_counter == 1);
assert(reader.read_counter == 2);
assert(reader.close_counter == 3);
Another simple pattern is the tracking of parameters passed to a mock object. Every parameter is stored in a vector. After completion the size of the vector and each expected value is checked.
class StorageInterface
{
public:
virtual void store(unsigned i) = 0;
};
class StorageMock : public StorageInterface
{
public:
std::vector<unsigned> params;
virtual void store(unsigned i)
{
params.push_back(i);
}
};
////////////////////////////////////////////
// The test within your testing framework
StorageMock store;
myMethodUnderTest(&store);
assert(store.params.size() == 2);
assert(store.params[0] == 123);
assert(store.params[1] == 456);