Some friends posted articles about TDD some time ago, which aroused a warm response. I have been studying and practicing TDD for nearly a year and want to share my understanding of TDD. This article discusses the essence and blind spots of TDD, and hopes to guide TDD beginners to understand the famous conclusion that "TDD can drive a better design.
Essence of TDD
Most of the first thing that comes to our minds when it comes to TDD is this classic iterative flowchart:
However, I think the purpose of this image is only to compare it with the traditional development process. It is more of a form. What this image does not cover is:How do I write test cases?This problem has basically reached a consensus: TDD test cases must come from functional requirements. We can have different ways to express functional requirements, such as natural language documents and UML Use cases. TDD test cases should also be an expression of functional requirements specifications. Therefore, when writing test cases, we treat the tested system as a black box and place the black box in an application scenario that expresses Functional Requirements Specifications. For example, for Stack, the functional requirement is FILO. Therefore, we should use the Stack object as a black box in the scenario of checking FILO. BDD clearly shows that TDD lacks the description of how to write test cases, and it must be a use case. We may consider TDD testing cases as an executable requirement specification. Therefore, it facilitates rapid feedback on implementation and refactoring. To describe the essence of TDD in one sentence, I will add a sentence next to the TDD iteration flowchart.Test Case is executable specification.
TDD blind zone
TDD test cases have such advantages over document and Use Case in expressing requirements. Can TDD ensure the development of high-quality software? Let's first think about what is the driver of software development? Is the test in the driver? Of course not! Testing is still driven by requirements, even in TDD.
Dynamic Model of traditional software development:
Analyze user requirements => extract the required specifications => design according to specifications => write code implementation design => write test cases...
The dynamic model of TDD software development:
Analyze user requirements => extract the required specifications => write test cases according to the specifications => write code to pass the test...
I understand that software development is demand-driven. The above dynamic model is too crude and does not reflect the process of program development. The requirements of system A determine the external characteristics of A. In TDD, we can use the corresponding test cases (including acceptance test and unit test) to express the requirements for. However, to overcome system complexity, we usually divide A into several subsystems a1, a2, a3 ,..., in addition, various subsystems are associated to form an overall function. This is the internal design of. The internal design of system A generates the requirements for subsystems a1, a2, a3. Although at the subsystem level, TDD can also help us express our needs with test casesTDD's blind zone lies in its inability to drive the internal design of the system.! It is impossible for us to directly launch A's internal module decomposition through TDD and how subsystems work together. We often hear that "TDD drives a better design", and this sentence must be correctly understood. "TDD drives a better design" involves two aspects: 1. TDD first focuses on the system's external interfaces, checks the interfaces in specific application scenarios, and provides feedback on the external interface design before implementation; 2. after the internal design of the system is completed, TDD can help decouple subsystems to avoid non-essential coupling between subsystems. TDD cannot help with how system A is decomposed into subsystems a1, a2, and a3.
Relationship between requirements and design
If you broaden your horizons, any system will be in a larger system, and the requirements of the system will often come from the design of upper-level systems. The actual development process is also the upper-layer design that generates lower-level requirements. If TDD test cases are written based on scientific methods, system design is an art. Only by understanding the relationship between demand and design can we grasp the positioning of TDD in software development and learn its essence without exaggerating its effect.
Summary
This article is a summary of one year's self-learning and practice of TDD. If there are any mistakes in this article, you are welcome to correct them and discuss them!