A gentle introduction to TDD
The content here is under the Attribution 4.0 International (CC BY 4.0) license
According to Kent Beck [1] TDD is a bit nebulous, TDD is an awareness of the gap between decision and feedback during the programming phase. Beck mentions the gap between feedback and the program, aiming at the difficulty for programmers in having a quick response at the moment they are writing the code. Often the writing process by the programmer follows three basic steps:
- The first is writing the code
- the second is testing and
- third is refactoring in case something is wrong or there is a need to change the code.
Here the hypothesis is created that with the evolution of graphical interfaces and the evolution of flows for carrying out tasks in the systems, the programmer is at the forefront of executing extra steps to get to the point where your code can be tested, thus delaying feedback if the code is working as expected. In that sense, Test-Driven Development (TDD) has three stages to shorten the feedback. TDD works in the following manner:
- Red Phase (Write a Failing Test): In this initial stage, developers write a test that defines a function or improvements of a function, which should be very specific and fail because the function is not yet implemented or the improvement does not exist. This phase helps in clearly defining the expected behavior of the code.
- Green Phase (Write the Code to Pass the Test): In this stage, developers write the minimum amount of code necessary to pass the test written in the Red phase. The focus is on writing code that fulfills the requirements of the test without considering design or efficiency. This phase ensures that the code meets the specified requirements.
- Refactor Phase (Improve Code Quality): After the test has passed, developers refactor the code to improve its design, readability, and efficiency without changing its behavior. This phase aims to eliminate any technical debt, improve code quality, and ensure that the codebase remains maintainable and scalable.
If the theory is a bit difficult to grasp at first, no problem, I felt the same. To remediate that Dave Farley shows live coding the three steps of TDD in the style known as classicist TDD, he uses Python and the fizzbuzz kata.
Katas are a section in itself in this content and we will dive deeper into them later. The key takeaway here is to see how katas can be a way to train new techniques. TDD comes with other areas of knowledge as well, the practice shows that it supports an agile environment, increases internal code quality, gives a safety net for refactoring, allows design improvement and guides to understand the domain from a test first point of view.
In that sense, TDD is not a magical thing that once incorporated will solve all the problems with the software. TDD is a portion of what is needed to build quality software projects.
Why TDD at all?
As trivial as it seems, answering the question of why TDD is trickier than it sounds. The industry has long challenging the TDD cycle which led to a discussion between Kent Beck, Martin Fowler and David. More recently Dave Farley also published another video supporting the TDD practice. For many, writing the test before the production code still makes no sense.
All in all, TDD contributes to the development process in the following ways:
- Ensuring Test Coverage: By writing tests before implementing the code (Red phase), developers ensure that the codebase has comprehensive test coverage, which helps in identifying and fixing bugs early in the development process
- Promoting Incremental Development: TDD encourages developers to work in small, incremental steps by writing tests and code in short cycles. This iterative approach allows for continuous feedback and validation of the codebase. In 2012 continuous feedback is one of the attributes mentioned by practitioners, it permits the short feedback cycle and enables the immediate correction of design decisions taken [2]
- Improving Code Quality: The refactoring phase in TDD focuses on improving the design and structure of the code without changing its behavior. This continuous improvement process helps in maintaining a clean and efficient codebase
- Facilitating Collaboration: TDD promotes collaboration among team members by providing a clear set of requirements through tests. This shared understanding of the codebase and its behavior enhances communication and teamwork within the development team
- Enables new ways of working The practice of TDD at a team level supports the Trunk-Based Development flow for fast integration and fast feedback
Overall, the three stages of TDD contribute to a more structured, efficient, and quality-oriented development process by emphasizing test coverage, incremental development, code quality, and collaboration among team members.
TDD styles
Sandro Mancuso and Robert Martin created a comparison video series discussing the London vs. Chicago styles to illustrate the differences and benefits of each approach. The video series can be purchased, the introduction is available for free on YouTube.
The outside-in style is closely related to the history of test doubles and how they were created, emphasizing the importance of using test doubles in TDD practices [3].
Chicago School (Inside-Out)
This style focuses on starting with the business stages first and defining the interactions that objects should have to fulfill a given requirement. It serves as a learning path where developers work on fulfilling specific business requirements step-by-step. The book “TDD by Example” by Beck uses a calculator as a fictional business requirement to guide learners through the implementation process.
London School (Outside-In)
This style starts with the client of the application, such as an API or a graphical user interface, and then delves into the inside where the business stages are written and fulfilled. Also known as TDD double-loop, this style emphasizes starting from the external interfaces and working towards the internal implementation. It provides two levels of feedback, focusing on the client-facing aspects of the application and then moving towards the internal business logic.
A working skeleton for outside-in?
One of the challenges to start with outside-in is to have a proper setup to start writing the outer loop. To that end, the getting started with outside-in offers a quick start quick with reactjs, Cypress and testing-library.
Outside-in React Development by Josh Justice
Josh Justice self-published the book “Outside-in React Development” with his thoughts on the TDD style. YouTube hosts a plethora of videos of practitioners writing code with outside-in.
What is the best style?
The choice of the best style of Test-Driven Development (TDD) between the Chicago School (inside-out) and the London School (outside-in) ultimately depends on various factors such as the project requirements, team preferences, and individual developer comfort levels. Both styles have their strengths and can be effective in different scenarios.
Developers and teams are encouraged to explore both styles, understand their strengths and weaknesses, and choose the style that best suits their project requirements and development practices.
TDD is often related to other subjects
searching for the subject of testing development often comes with other practices around it not only TDD itself but rather a combination of practices that aim towards better quality of the software development. For example, the meetup technical excellence. Often hosts meet up about TDD and architecture.
The book “Technical Agile Practices” by Santos et al. is another example. The book brings to attention different practices and different perspectives that fit with TDD [4].
Can Artificial intelligence help TDD?
In the era of IA for all fields and the boom of new technologies such as ChatGPT, the areas of knowledge that are specific to a target audience can also benefit from it. In a recent study by Baudry et al.[5] test data was generated using generative IA. The results suggest that the set of data generated by it is accurate and it also enumerated other libraries that are using IA.
What are the impacts for teams that use TDD?
- Improved Code Quality
- TDD encourages developers to write tests before writing the actual code, leading to a focus on creating code that meets specific requirements.
- By continuously running tests during development, TDD helps identify and address defects early in the process, resulting in higher code quality and fewer bugs in the final product.
- Reduced Debugging Time
- With TDD, developers can catch and fix defects at an early stage, reducing the time spent on debugging later in the development cycle.
- By having a comprehensive suite of automated tests, organizations can quickly identify regressions and ensure that new code changes do not break existing functionality.
- Enhanced Collaboration
- TDD promotes collaboration between developers, testers, and other stakeholders by encouraging clear communication and a shared understanding of requirements.
- Teams working with TDD often have a shared language around tests and requirements, leading to better collaboration and alignment on project goals.
- Increased Confidence in Code Changes:
- TDD provides developers with a safety net of automated tests that can quickly validate code changes and ensure that existing functionality is not compromised.
- This increased confidence in making changes to the codebase can lead to more frequent updates and improvements without the fear of introducing unexpected issues.
- Support for Continuous Integration and Deployment:
- TDD fits well with continuous integration and deployment practices, as automated tests can be run regularly to ensure that code changes do not introduce errors.
- Organizations using TDD in conjunction with CI/CD pipelines can streamline the development process and deliver software updates more frequently and reliably.
What are the challenges of adopting TDD?
- Mindset Shift - Transitioning to a TDD approach requires a shift in mindset for developers who are accustomed to writing code first and tests later. Embracing the “test-first” philosophy can be challenging for those not familiar with TDD practices. Developers may need to invest additional effort to master TDD practices and effectively integrate them into their workflow [6].
- Learning Curve - Developers may need time to learn TDD practices, including writing effective tests, understanding test coverage, and integrating testing into their daily workflow. This learning curve can impact initial productivity as developers adapt to the new approach.
- Apply TDD in legacy code bases
Does TDD take longer to develop?
TDD may initially slow down development speed as developers write tests before implementing functionality. Meeting project deadlines while adhering to TDD practices can be a balancing act for teams. However, the industry has challenged this idea. Martin Fowler wrote about the trading quality hypothesis that elaborates on the subject. The Pragmatic Programmer also touches on this point
TDD vs BDD
TDD and BDD both involve writing tests as part of the development process, TDD focuses on writing tests at the unit level to drive the design and implementation of code, while BDD focuses on defining and verifying the behavior of the system from a higher-level, business-oriented perspective. BDD can be seen as an extension of TDD that in
References
- [1]Beck, “Test Driven Development: By Example.” Addison-Wesley Longman Publishing Co., Inc., 2002.
- [2]M. F. Aniche and M. A. Gerosa, “How the practice of TDD influences class design in object-oriented systems: Patterns of unit tests feedback,” in 2012 26th Brazilian Symposium on Software Engineering, 2012, pp. 1–10.
- [3]M. Marabesi, A. García-Holgado, and F. J. García-Peñalvo, “Exploring the Connection between the TDD Practice and Test Smells—A Systematic Literature Review,” Computers, vol. 13, no. 3, 2024, doi: 10.3390/computers13030079. [Online]. Available at: https://www.mdpi.com/2073-431X/13/3/79
- [4]P. M. Santos, M. Consolaro, and A. Di Gioia, Agile Technical Practices Distilled: A learning journey in technical practices and principles of software design. Packt Publishing Ltd, 2019.
- [5]B. Baudry et al., “Generative AI to Generate Test Data Generators,” arXiv preprint arXiv:2401.17626, 2024.
- [6]S. M. Tampubolon and T. Raharjo, “Unveiling the Benefits and Challenges of Test-Driven Development in Agile: A Systematic Literature Review,” Indonesian Journal of Computer Science, vol. 13, no. 2, 2024.
Additional resources
- My path to Test Driven Development
- TDD by example book review
- Triangulation in Test-driven Development
Throughout this journey of learning TDD and researching the subject a playlist with many videos about TDD was created and hosted on YouTube:
Table of contents
Got a question?
If you have question or feedback, don't think twice and click here to leave a comment. Just want to support me? Buy me a coffee!