The gentle art of deception
Writing code kata’s is fine, you end with a small class, that has no dependencies connects to nothing, doesn’t need a network, service or database! So what do you do when you are trying to do good tdd in the real world?
Unit tests should be run frequently, which means that there should be no time penalty for running the tests, so the tests need to be quick, and because they are going to be run so often they also need to be repeatable.
Connecting to the database or running over a network takes time, and the more production code each test calls the closer that test is probably tied to the current implementation, this creates fragile tests, which break easily with even small changes to either the data or the production code.
Creating fragile tests is bad, there is nothing worse than doing a perfectly sensible refactoring, and discovering that 50 tests have broken, or simply loading an old project from source control and discovering that because all the data has changed, none of the tests will run correctly. Developers lose confidence in the whole concept of the tests, and the test suite, when things like this happen, which results in the tests not getting run, and all the advantages of having a test framework are lost. Once you comment out, ignore, or delete a test, the production code that is covered by that test becomes legacy code and is a debt to the software instead of an asset.
So each unit test needs to cover the smallest amount of production code possible, but still have meaning, without relying on external sources of data or functions. So how do you test a method that gets data from the database?
So if we write a test class like this
We have a brittle slow running test! It relies on the database and the record being in the database to pass, so its going to be time and data dependent all of which could cause the developer not to run the test as often as they should, or in the worst case actually delete it.
So what can be done?
We need to fake the database, so that the only code that is actually being tested is the code within the method we are calling. this is done very easily simply by writing a class that implements the correct interface and stub out the method that is called, in this case returning some canned data.
Now the test is totally independent of the database, the test data coming back is canned so it is guaranteed to always be the same, and because its just all code, the test runs very quickly. But I am not testing the gateway class! Which is true, this class would have its own batch of tests, which when run test its functionality, again without reference to the database, each class in the whole application should be tested this way, independent of as may other external sources as possible, using fake objects to represent each of the objects dependencies.
This is all a mock or stub object is, a dummy object that behaves in a predetermined way, and may if required monitor its inputs and other parameters. Here I have rolled my own fake object, which sometimes is the best solution but there are many frameworks out there like RhinoMocks and Moq, which create fake objects automatically from a given interface, and provide services that allow you to raise events, return multiple values and many other functions for testing using fake objects.