Had an interesting talk with a colleague of mine some time back on the topic of retrofitting tests to a system. I'm not a fan of retro fitting for the sake of it. The, now hopefully well documented, problem with TDD is that the 'test' bit is a side effect. Its practically a distraction to the design aspect of TDD. So when I get told to write 'unit' tests against an code base, I accept they are not going to be the same sort of unit tests as those that I would write when I'm doing test first.
So why do I have an issue?
When we retro fit unit tests, the best we can do is make observations of the current state of the system. This system may be subtly wrong, how can we know if we have no specification to verify against? At the unit level such detail may not be understood by the business. The scenario that the code was written under is most likely forgotten or more likely misunderstood. So when we write tests we merely observe and report, we cannot say that we understand.
I came across this issue, yesterday. My pair and I were refactoring some code and saw a redundant switch statement. looking at the system hollistically, it was obvious that the code didn't belong so we whipped it out, ran the tests and got red.
The production code was something like this:
public string GetContent(int fooId)
{
var content = string.Empty;
switch (fooId)
{
case 4:
return _contentModule.GetContent();
}
return content;
}
We knew that fooId would only ever be 4, (cough magic number) and so could simplify this method down but when we ran the test, we failed on:
public void Should_return_stringEmpty_when_fooId_not_equal_to_4()
When I looked at the log in source control it revealed that the tests had been committed 3 months after production code had. I'm guessing then that the test author had merely looked at the code and applied a test based on what the code actually does rather than the intent.
This retro fitting of tests can therefore be dangerous. If we trust the tests (and we should) then retro fitting can be misleading and it is against the TDD ethos. Remember kids you should value specifying over verifying.
So why do I have an issue?
When we retro fit unit tests, the best we can do is make observations of the current state of the system. This system may be subtly wrong, how can we know if we have no specification to verify against? At the unit level such detail may not be understood by the business. The scenario that the code was written under is most likely forgotten or more likely misunderstood. So when we write tests we merely observe and report, we cannot say that we understand.
I came across this issue, yesterday. My pair and I were refactoring some code and saw a redundant switch statement. looking at the system hollistically, it was obvious that the code didn't belong so we whipped it out, ran the tests and got red.
The production code was something like this:
public string GetContent(int fooId)
{
var content = string.Empty;
switch (fooId)
{
case 4:
return _contentModule.GetContent();
}
return content;
}
We knew that fooId would only ever be 4, (cough magic number) and so could simplify this method down but when we ran the test, we failed on:
public void Should_return_stringEmpty_when_fooId_not_equal_to_4()
When I looked at the log in source control it revealed that the tests had been committed 3 months after production code had. I'm guessing then that the test author had merely looked at the code and applied a test based on what the code actually does rather than the intent.
This retro fitting of tests can therefore be dangerous. If we trust the tests (and we should) then retro fitting can be misleading and it is against the TDD ethos. Remember kids you should value specifying over verifying.