We all know why testing our software is important – how would we know whether our code is doing what we intend for it to do otherwise? But sometimes, when writing tests at the end of implementation becomes tedious, time-consuming, and only done for the sake of doing it, it can be worthwhile to look at a different approach of development. And yes, for those who are already familiar with testing, I’m talking about test driven development (TDD).
For those who aren’t, TDD involves first writing a test based on the requirements of the code before actually implementing, running the test, and watching it fail. If the test passes, either the feature you are implementing already exists in the current code or the test isn’t correctly checking for the requirements. The code is then implemented to meet the requirements until the test passes, and the test is then added to the automated regression test suite that is run regularly to catch bugs that may have been introduced in new development. If the tests fail at any point after verified functionality, it must be in the code that has just been affected. Once all the tests pass, the code can then be refactored to remove duplication without having to worry about unexpected consequences.
This approach is useful as it requires the developer to think about how the software will be used and how to validate that the product has met the requirements. TDD is a tool for applying automated tests that are generally unit tests, but can be used with integration and acceptance tests. Acceptance TDD (ATDD) and behaviour driven development (BDD) apply TDD at a higher level of the system design. ATDD contains detailed executable requirements that the project stakeholders agree upon, while BDD describes how to write good tests in TDD. The idea is to test the behaviour of the software instead of the implementation details, so that a change in code implementation does not require a change in the test as the overall behaviour of the software should not be affected.
An instance of TDD working well was demonstrated in our project with Manitoba Blue Cross. Aversan provided Independent Verification and Validation (IV&V) services that uncovered gaps in requirements and defects in the system. This helped to drive the development of the project and improved test coverage. You can read more about the project in our previous blog post, “You’re spending too much time testing software”!
Don’t get me wrong, I’m not here to tell you how you should and shouldn’t write your code, but there is definitely merit in exploring a different approach if it makes doing what you need to do a little easier. You shouldn’t follow TDD blindly just because someone tells you it’s the “right way”, and especially not if it harms the design of your code, but it’s an interesting concept to consider as it provides a different perspective in developing. For example, it could make it easier to get into the habit of writing tests if they were written before implementation. It can also make it easier to validate your code while you are implementing since your code can be validated the minute it is written. That being said, this approach works best if the outputs of the system are clearly defined and testable.
Certainly, there are challenges to TDD. For one, TDD requires more setup time and investment early on, but ensures that requirements are met throughout. With that said, maintaining the test suite for projects without well-defined or with constantly changing specifications will be more costly. Not to mention, creating these tests in the first place will be difficult already. So the bottom line is, use an approach if it will help your design, and if you’re trying too hard to shape your design so that you can use a certain approach, then it’s probably the wrong approach.
Disclaimer: Any views or opinions presented in this blog post are solely those of the author and do not necessarily represent those of Aversan Inc.