Skip to content
  • There are no suggestions because the search field is empty.

It's Okay to Take a Relaxed Approach to TDD Implementation

Recently, there have been discussions about whether we can discard test code in Test-Driven Development (TDD). Based on personal experiences, I believe that TDD can still be effective even if we treat test code as disposable.

Of course, writing maintainable and valuable tests using TDD and reusing them through Continuous Integration (CI) and long-term refactoring can amplify the benefits of TDD. However, achieving this requires skills, pre-planning, and effort, and it may not be applicable in all situations.

Despite that, I think TDD can still yield cost-effective results without undertaking these additional efforts. Let's explore some practical points where we can adopt a more relaxed approach to TDD based on my experience.

 

sigmund-rWE7bTqgMJE-unsplashPhoto by Sigmund on Unsplash

 

It's okay to treat tests as disposable. 

In TDD, tests are incrementally created to address various programming challenges, which can result in tests that are costly to maintain or provide low value. Thus, it is natural to create disposable tests.

Since in TDD tests are created cumulatively in response to the programmer's various issues, tests that are expensive to maintain and tests that are not worth maintaining are apt to be created. Therefore, disposable tests are a natural occurrence.

Also, since tests can be created with light motivation, such as to resolve programmers' concerns, TDD can be effective even with a style in which tests are written with a light motivation and discarded with a loose judgment.

【To Elaborate】Of course, if we can increase the number of tests that can continue to be reused in TDD and incorporate them into CI, etc., we can amplify the cost-effectiveness of TDD. However, to do this, it is necessary to ensure test maintainability (reorganization of test code, etc.), to have test design skills to create effective tests, 
and to have skills and make effort to ensure testability.. Furthermore, there is a limit to the situations in which it can be applied. I think it is safe to start working on such things from the next step after you are able to successfully turn TDD around on your own. It is also important to recognize that this is only possible in some cases.

 

It's okay to casually and subjectively determine the coverage of tests.

The sufficiency and coverage of tests in TDD can be judged subjectively and roughly. For example, if you feel uneasy during programming, it is sufficient to test until you feel that your uneasiness is gone subjectively. Tests in TDD can be effective without logical test design by systematic testing methods and techniques.

On the other hand, if you try to proceed with rigorous test design using techniques you are not familiar with, you will slow down the process, and the cost-effectiveness of TDD will decline.

【To Elaborate】 If you learn systematic testing methods and techniques, and you can easily secure effective tests, you will be able to write effective test code even for TDD. However, this comes after you are able to run TDD, and I think one should take it step by step.

 

It's okay to implement TDD in limited parts of software development. 

It may go without saying, but TDD cannot be applied to all of your code. TDD can only be effective in areas where automated testing can be easily applied. In other areas, it is likely to fail or not be very cost-effective.

Therefore, if you find TDD difficult to perform, you can stop. Even if only 20% of the programming can be done with TDD, it is a good thing if that 20% is effective.

【To Elaborate】It’s vitally important to work on testability for automated testing at the architecture level if you aim to expand TDD’s applicability (TDD contributes to ensuring testability on the unit level but we must work on the architectural level to tackle more issues). This is a good challenge to take on after you are able to successfully implement TDD widely.  

 

It's okay to write tests ex-post. 

Although one would technically be leaning away from TDD, tests can be written later. One of the important premises of TDD is a habit of making programming efficient by using unit tests effortlessly like an extension of yourself. For example, in the case that you are not sure about specification, you would you would nimbly write tests with Test-First approach., and when you are not sure about the code you have written, you would nimbly add tests.

If you continue the habit of casually using unit tests, regardless of if you test first or code first, you will be able to fulfill this premise and practice TDD at a much faster pace.

So there is no need to feel self-conscious about writing tests later. What is important is to use unit tests casually and nimbly in your programming.

 

It's okay to not test a unit. 

It is sometimes easier to write effective and solid automated tests at larger granularities such as packages and on the architectural level. If it’s the case, just do it- execute your test at a large granularity (just like the typical TDD double loop and Outside-In TDD of object-oriented selection). Never be held back by the theoretical principle that “in TDD, tests should be written for units (the smallest unit of codes)”, focus on cost performance and start your process with some easy-to-write granularities.

【To Elaborate】To write tests at larger granularities, it is essential to ensure a solid, durable, and automated test-friendly interface on the granularity of packages, layers, and boundaries at the architectural level. This interface enable us to attain effective and solid tests in TDD.

 

It's okay not to get the whole team involved in TDD. 

TDD can also be cost-effective when it’s just executed by one single member. 

As a programmer, you will encounter many situations where you want to review code specifications, feel the risk of defects, or want to refactor your code. TDD is an easy way to solve these problems on an individual level.

On the other hand, if the cost-effectiveness of TDD is negative for an individual, and the entire team has to do TDD to make it cost-effective, there is a strong possibility of a problem with the way TDD is performed. (this is often due to a lack of speed or testability implementation skills of the team as a whole. Or they may be trying to be too perfect with TDD and not take the aforementioned casual approach).

【To Elaborate】 It’s crucial to get the whole team involved if you aim at sustainable test usage of CI. What you need is thorough preparation of a developmental infrastructure and practical skills. And to some extent, we need to propel TDD at the team level to use tests sustainably.

 

Some additional thoughts: reducing disposability and making TDD testing more cost-effective

 TDD works well even in a one-off approach based on programmers’ subjective judgments. Once you’ve achieved this, you might want to try the following steps to boost TDD implementation (TDD testing helps to enhance these, not guarantee them), reduce one-off tests, and improve cost performance.

  • Create durable tests for continuous use for regression bug detection and refactoring.
  • Create effective tests to spot bugs efficiently and guarantee quality.

Note: We cannot expect tests created by TDD satisfies the above as is, but by improving them they can satisfy the above.

If the focus is on individual activities, the following skills are required to take TDD to the next level:

  •  Skills to guarantee the testability of automated tests
    • Architectural design ingenuity is required - localizing and isolating elements that hinder test automation, separating code into independent packages so that we can write automated tests, and establishing a design policy that allows unit tests to be widely executed.
  • Skills to create maintainable tests
    • These include making the tests more resistant to changes to the test target (improving modifiability), improving the coupling and cohesion of the test code, and making the test code more readable and maintainable.
  • Skills to design effective tests
    • This is the process of deciding necessary tests and designing them appropriately. It requires a mastery of risk-based testing and various techniques for creating valid and exhaustive tests.

In order to level up with TDD, we need to reinforce TDD activities by more comprehensive (or higher layer or large-grained) test cycle activities such as quality assurance strategizing (identifying test requirements for what responsibilities should be fulfilled by reusing tests in TDD), test code improvement and refactoring, test design improvement, and Outside-In TDD. 

And to some extent, we need to propel TDD at the team level to reuse tests: CI and shared test automation environments need to be in place, and teams need to be in the habit of continuously improving and maintaining their tests.

 

This article was originally written in Japanese, and translated for TestingPod with permission from the original author. Check out the original article here

 

Hiroki Iseri

Written by Hiroki Iseri

Engineer of Digital Cockpit Software Development Section, and actively contributes to technical leadership in test teams and project QA. Serves on the Japan Software Testing Qualifications Board and as the Founder-Chair of ASTER U30 Test Design Contest. Notable works include translations of software engineering texts and impactful presentations.