Software Engineering

Tuesday, August 01, 2006

A Mockery of Mock Objects

Mock objects are emulations of real objects except without any implementation. These emulations have their outputs already defined before they are used. Typically unit tests that utilize mock objects will use them to mock various contingencies such as: emulating a specific interaction with the tested object, and setting up test return values on initialization objects. Mock objects seem appealing and catchy at first, but if you really think about it they aren't very useful. Don't waste your time learning Mocking Frameworks.

A lot of people would argue that one must mock an object because the real object is too difucult to initialize and setup for a unit test. Well, really if it is that difficult to set up, then one should refactor the real object so that it is simple to use. After all, simplicity is what we are all after when designing an object model anways, isn't it?

Another problem I have seen from very intelligent software engineers is that they get over enthusiastic about mocking objects. I have been on a team where the software engineers literally forced a test to pass by mocking too many objects. They mocked too many objects within the unit test forcing it to pass. It was like a teacher handing you a test with all the answers already filled in for you! The test did not test anything; it was set up to pass before it even ran! Needless to say the test passed, but there where numerous errors in the code.

Mocking object interactions is actually the root of the problem. When one mocks an interaction, then regression testing is no longer possible. For example, lets say you have an object A that object B implements internally. Object B calls a method of object A. In Object B's unit test, object A is mocked and the method called is set to return a value X. Object A's method implementation is now changed to return a new value Y. Since object B has mocked object A and its return value has been mocked, then object B's unit test still passes with flying colors! Object A's unit test will also pass with flying colors. But, the real applicaiton will fail. This could have been prevented if no mock objects were used.

Additionally, for those that feel like they "need" to mock objects for a particular situation, I can show you how to reproduce that situation without mock objects. Whenever you feel like you need a mock object you are developing code that is not testable or you are just being lazy.

The problem with mocking objects is that issues between object interaction passes by the "Daily Build and Smoke Test", or continuous integration, undetected. Because issues between object interactions aren't detected during continuous integration due to mocking interactions, then that means these issues won't expose themselves until functional/acceptance testing. By this point it is too late in the game! It is too late because typically acceptance tests are ran at the end of the iteration which could be thirty business days! Now, you have thirty business days worth of code to sift through in order to find the bug. If your lucky the bug will be detected at runtime during acceptance testing, but again too late in the game. Waiting for acceptance tests to catch problems with object interactions is just too late and unacceptable!

For more information and discussions about avoiding mock objects, visit these related posts (I will add more links to related articles as I find them. If you have any comments or links, then please feel free to add them to the comment section):
http://agiletesting.blogspot.com/2006/03/should-acceptance-tests-talk-to.html