Is it recommended that TDD be always practiced in a project, or are there cases when it should be avoided?
Should we all adopt TDD?
Is it standard practice in major software companies?
Software Engineering Stack Exchange is a question and answer site for professionals, academics, and students working within the systems development life cycle. It only takes a minute to sign up.Sign up to join this community
Factors Limiting Industrial Adoption of Test Driven Development, a research paper from 2011, reviewed 9,462 papers on TDD, and included 48 studies as a basis for their research. The paper covers the topic of why TDD may not be used in depth, but for ease of reference, here's a summary:
- Development time: Development time could be considered a business-critical factor for adopting new practices within an organization. Depending on the maturity of the organization, an up-front loss (in this case, increased development time) might overshadow a long-term gain (e.g., decreased overall project time, or increased product quality – both of which were reported in many of our included studies). Hence, internal organizational pressure might risk the proper usage of TDD.
- Experience/knowledge: When observing collected data from the included primary studies, we noticed that participants in the experiments (either students or professionals) were mostly provided with some training or tutorial on how to perform TDD. In several cases, the knowledge improved as participants would progress with the experiment. We expect that lack of knowledge or experience with TDD could create problems in its adoption.
- Design: There is no massive empirical support that the lack of design should be considered as a limiting factor for industrial adoption of TDD. However, there are a handful of studies reporting problems regarding lack of design in TDD, particularly in the development of larger, more complex systems. Moreover, the lack of upfront design has been one of the main criticisms of TDD since its introduction and even if the evidence supporting this criticism is sparse, so is the evidence contradicting it.
- Skill in testing: Since TDD is a design technique where the developer undertakes development by first creating testcases and then writes code that makes the test cases pass, it relies on the ability of the developer to produce sufficiently good test cases. Additionally, one study reports on the risk it brings to adopt TDD without having adequate testing skills and knowledge. We find it interesting that there are no explicit investigations of the quality of test cases produced by developers in TDD.
- TDD adherence: The combined view of five industrial case studies state that the inclusion of the lack of TDD adherence as a limiting factor. Basically, the studies state that (1) it is important to adhere to the TDD protocol, and (2) developers do stray from the protocol in several situations. It is however far from certain that there is a clean-cut cause-effect relationship between low TDD adherence and low quality. Not unlikely, confounding factors (e.g., tight development deadlines) might lead to both low TDD adherence and poor quality
- Domain and tool specific issues: Proper tool support for test automation is vital for the successful adoption of TDD. With the wide variety of studies reporting domain- and tool-specific issues as a limiting factor in the adoption of TDD, the factor would be difficult to ignore.
- Legacy code: TDD, in its original form, does not discuss how to handle legacy code. Instead, the method seems to assume that all code is developed from scratch, using TDD as the development method. As this is seldom the case in large development organization, adoption of TDD might be problematic. A lack of automated regression suites for legacy code hampers the flexibility provided by the quick feedback on changes provided by the regression suites, and may leave developers more anxious about how new changes may unexpectedly affect existing code.
I think it all comes down to a simple question: Does it have to work? If it does, then I would say it is best to do TDD, on the majority of cases.
To me, the exceptions are very lightweight pieces of code. Weight the effort of manually testing every single procedural branch in the code. If this effort is smaller than that of writing automated tests, then I'd say it wouldn't be a problem to not do TDD. By the way, if you have to run the manual tests more than once, that effort is multiplied.
So, if we think about it, there's hardly any useful kind of software to which the effort of manually testing (multiple times) would be lower than writing automated tests. I can only think of small proof-of-concepts and demonstration code, but even then I'd prefer to practice TDD, because such prototypical code may grow to become full functioning software.
Now, as for TDD as official practice in major companies, I can only answer based on the company I work for, and no, it isn't. There are companies that require unit tests to be written by the end of an iteration, with an "acceptable" range of code coverage, but that is completely different to practicing TDD.
In any case, we, as software developers, professionals, have to decide whether or not to practice TDD, not our contractors.
TDD shouldn't be used when some alternative approach is more appropriate. The key thing to remember is that the alternative approaches aren't so much manual testing, as things like:
Automated testing being especially difficult for some reason is one factor that might guide the choice of design method. But it is far from the key factor; in fact several of the other approaches will end up doing as much, or more, automated testing than TDD.
One thing I learned about dealing with legacy code which I did this for medium and big projects with > 1 million lines of code, it makes sense to use TDD here as well. But it is much harder to get your code there in tests.
Normally legacy code bases doen't have any tests in place so fixing a bug and writing a unit test for it is a good starting point to get some. But normally you have to refactor the code a little bit before you can write these tests. There is a really good book out where you can learn a lot about TDD with legacy code ( breaking dependencies, how to write the first test and so on ) : http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052