Too often I hear, “the client won’t pay for unit tests” or “I don’t like writing tests”. Ok. If you can guarantee a high level of quality and productivity without tests, go for it.
Sadly its these same individuals and teams that have devoted days, weeks, or entire sprints to fixing bugs. What if I said, “bugs will be fixed during lunch and on the weekends, and will not be considered billable work.” Would you have the same opinion?
What if you were held monetarily accountable for any defects in the system? What if some code you wrote cost your company thousands of dollars? What if it cost them millions? What if it cost someone their life?
Increasingly the world is being run by software. The importance of software being accurate has never had a higher priority.
“QA should find nothing”
-Uncle Bob Martin
Unit testing can really save time and effort. Have you ever chased the same bug for weeks, only to have it crop up again later? You thought you had it fixed, but with another change it reared its ugly head again. What if you had a way to ensure a bug was licked, given a certain scenario?
Unit Tests provide that assurance. When you find a bug, write a test covering that scenario. Write more than one. If a similar bug crops up, and your tests still pass, you can rest assured that this is a new scenario and merely requires a new test (and a code fix).
You also now have the added benefit of low-level documentation that never expires. We’ve all unearthed an ancient specification document that is woefully outdated. If you try to make sense of a current system with an obsolete spec, you’re in for some heartache. Passing Unit Tests will tell you quite clearly what a system currently does.
Integration Tests are a great way to ensure that a system’s components are working together correctly. If you’ve got good coverage with your Unit Tests and a broad collection of Integration Tests, your confidence when it comes time to ship should be quite high indeed. If not, perhaps its time to evaluate the parts of the system to give you pause.
I’ve been a part of some projects that would ship if all Unit and Integration Tests passed at the end of any given sprint. Now, admittedly, these were generally low risk changes and enhancements to some non-mission critical systems. However, your confidence to ship should always be high.
Test Driven Development
One of the main benefits touted by TDD proponents is better design. While some may argue this point, it’s certainly true that you arrive at a simpler, high quality, easy to maintain solution.
My reasons for enjoying TDD revolve around the fast feedback of a passing (or failing!) test. The confidence to ruthlessly refactor while working on an application with a comprehensive suite of tests is liberating. Gone is the fear associated with making even the most minor change.
A great way to share the knowledge among team members is with code reviews. Knowledge of the system, as well as language features, patterns, and good coding practices can all be shared and discussed during the code review process. My preference is to have a more senior, more knowledgeable person review my code. I feel I’ve never learned more than when someone pointed out errors or improvements I could make in my own code.
Of course these reviews help deliver a higher quality product. Reviewers should take care to check for correctness against any requirements, user stories, and acceptance criteria; as well as adherence to any coding standards or style guides set by your team.
We are professionals. No one should have higher expectations of us than we have of ourselves. We should strive to continue to learn, to grow, and to deliver the highest quality product possible.