Why you're missing the point if you use a framework to generate mock objects for you...

| 3 Comments
Roy Osherove links to Mockpp a mock object framework for C++ and comments on how the framework is painful to use (and it looks like it was painful to write...) He concludes that he's getting on just fine writing his mocks manually... In my experience you'd miss a lot of very useful learning and design work if you didn't write the mocks manually...

If you're using a mock object to help you test a piece of code that's under development, that is, you're doing TDD or something close, then the act of creating the mock is useful for the design work that you're doing by doing TDD... Using a framework to create your mocks for you means that you don't get to experience as much of the "being a client of your own code" experience as you might otherwise, therefore it's something to avoid; IMHO...

TDD is all about the design. By writing a test before you write production code you think about the interface that clients of the production code will need to use. You're working as a client programmer and the tests will drive the design towards something that's nice to use from a client perspective. This is a Good Thing. In fact it's The Point!

When you write a mock object you're interacting with your production code in the way that a client would have to. Say your component takes an object that implements X, well, by writing a mockX you get to experience the pleasure (and pain) that a client would experience. If the component under test is buried deep inside your API then that client is YOU anyway... Writing the mock object is good for you (like eating your greens). If the mock is too hard to write then perhaps the interface you're mocking up could be better... If you just flick a switch and have some framework generate you a mock then you'll never know and you'll miss out on a valuable learning experience.

So, in summary, don't be a lazy arse, write your own mocks :)

I tend to use a simple test log class that just accepts strings and can later be tested to see what it contains and then construct my mocks something like this;

void CMockIOPool::Dispatch(
   IHandler &handler, 
   OVERLAPPED *pOverlapped,
   const DWORD numBytes) const
{
   LogMessage(_T("Dispatch")); // + ToString(&handler) + _T(":") + ToString(pOverlapped) + _T(":") + ToString(numBytes));
 
   handler.HandleOperation(static_cast<IBuffer*>(pOverlapped), numBytes, 0);
}
 
void CMockIOPool::AssociateDevice(
   HANDLE hDevice, 
   IHandler &handler) const
{
   LogMessage(_T("AssociateDevice"));// + ToString(hDevice) + _T(":") + ToString(&handler));
 
   m_iocp.AssociateDevice(hDevice, reinterpret_cast<ULONG_PTR>(&handler));
}

and this works pretty well for me...

Programming should be as simple as possible but not simpler. Sometimes I despair that people insist on going that extra mile to avoid a task and in doing so avoid the learning that comes from actually doing the task.

3 Comments

Have you ever had to write tests for legacy code with no existing tests? In many cases, you are talking about code that has passed heavy system testing. In this case, I would rather spend my time working on tests on new code, and on tests on refactored code, but still have some confidence that the old code hasn't been broken. Even on existing code, having repetitive, time consuming work done for me, like filling in parameters for a table with a hundred fields, saves me time, and suffers no loss of understanding ;-)

As for the learning, that can be a good point. But, there is an infinite amount of learning to be done, and you must choose very carefully how to spend that time.

I find the opposite. Stopping to create a mock class breaks the rhythm of test-driven development. That's why I use jMock to define mocked behaviour and expectations in my tests, without having to stop writing the test, write a mock class and then switch back to my test. With jMock I can write and run the test and then start fleshing out the real code by defining the mocked interface, adding methods to it, and so forth.

Obviously, in a language as static as C++ this style of programming is much harder, but a good mock framework is probably still useful.

Philip,

Yes, I've done quite a lot of work with testing legacy code. If you do a search for "refactoring project" you'll find the stuff I've written here about it.

We found that the first tests that you write for legacy code are usually very hard to write; so we tend to pick a point "high up" in the code structure so that we can test lots of code in one place. On the "refactoring project" this test point was at the top of the FX calculation code at the point where the display was updated. By hacking some tests in here and then spending a lot of time making sure that these tests hadn't broken anything we managed to make it reasonably safe to change any of the code below this point as the tests we had would show when things changed.

I can see that in this situation it may be easier to use a mock framework to create your mocks but in most of the legacy testing that I've done there were no interfaces to mock up so we had to both design the interfaces and then mock them up; so the learning was usually valid.

I think in languages like Java and C# you'd get more value from a mock framework simply because the framework can do more due to reflection, etc. In C++ this tends to be more of a manual process.

I agree you have to select your battles and decide which learning is worth persuing; so much to do, so little time...

Leave a comment