Ok so I am not the fastest adopter, however recent situations have almost forced me into a new way of thinking. Recently I was going over a fellow colleagues code and was about to add a test to one of his existing fixtures. He had previously mentioned that he felt there were a lot of tests, I told him not to worry, often when you are new to TDD it seems like a lot of extra code... I had underestimated his comments, he was right there was a ton of tests, thousands upon thousands of lines of tests, in one fixture. I had clearly not been doing my job and should have been helping him out.
The test were broken down into one fixture per class under test, using regions to separate out test groupings, typically for each method under test. There was some very basic common set up however there was still a lot of set up in each test. It became quite clear that there were certain common set ups that were occurring. Although the test per class is common it is usually not the best way of keeping your tests together, especially if you are being thorough in your testing. What my refactoring produced was akin to something I have been following for awhile but not really embraced, context based tests. The tests were broken up so those with common set ups were grouped in their own fixtures; i.e. those with the same defined stubs. Although in this case it was done to make maintenance easier it highlighted for me the benefits of this approach.
Fixtures become specific to the context in which they apply, not blindly and solely to the class they are testing. This will lead to lead to multiple test fixtures per class and multiple test fixtures per method. This is what initially turned me off the approach; fixtures would be come to fine grained, however I have changed tact. Although it may not always be appropriate I can see it being beneficial for many situations. For example you may emulate the Repository having no records in it (via a stubbed method call) and run a bunch of test with that context. This encourages you to test not just method calls but to think it terms of a given scenario, something that I see unit sometimes missing in the pursuit of just achieving code coverage. The fixture tend to have test that are very small and very clear as to what they are asserting, often only a couple of lines per test.
Another thing that originally put me off the notion of Context specification and BDD was the perception of tooling... RSpec etc are not required, it is the thought patterns that I think are more important. Setting up a specification can be done using basic setup method with each fixture defining a specific context. Test inheritance can be very helpful here too.
Although Context specification and BDD are not the same thing I believe they are a movement in the same direction; moving away for blind testing to defining scenarios that we need to test. Test become closer to one of the goals of being "readable documentation".
If you do what to read up a bit more check out:
Article introducing BDD styled tests with the notion of Context Specifications : http://www.code-magazine.com/article.aspx?quickid=0805061&page=1
A nice coding example showing one way of thinking in a context spec way: http://www.lostechies.com/blogs/rssvihla/archive/2009/05/21/context-spec-style-testing-and-my-approach-to-bdd.aspx
MSpec with Boo looks to be very cool too: (requires git client): http://github.com/olsonjeffery/machine.specifications.boo
Although the shift for me has not been great it has been significant, I would encourage you to at least investigate to consider if some of the principles can be applied in your testing.
No comments:
Post a Comment