I am a software development engineer who likes to pursue high-quality code and work efficiently, so I learn principles like SOLID and Simple Design, read good open source code, read books about it, learn about software process methods and real project practices, but on the road to high-quality code, I always feel that the current knowledge can not help me shape a thinking frame. At the beginning of 2018, I happened to read the TDD training record and was ecstatic!
I have been in contact with TDD for nearly a year now. During this period, I practiced TDD for a period of time because I could not keep my mind down and only read a few materials. I got good results and thought I had a good understanding of TDD practice and the ideas behind it. I found myself standing at the ignorant top of the “Darhk effect” curve, where most of what I thought was true was inaccurate or even wrong. However, I enjoy this process very much. It is very interesting to constantly verify my knowledge in the process of learning, which makes me more self-aware and constantly break my cognitive limit.
Next, I will summarize the practice and thinking of TDD during this period by means of pictures and pictures, so as to accumulate my understanding of TDD, hoping to be helpful to readers, and also hope that readers can give some advice and pool their wisdom to get closer to the truth.
The scope of
TDD (Test Driven Development) may have different understandings in different circles and different roles. Some people may understand it as ATDD (Acceptance Test Driven Development). Some people may also understand UTDD (Unit Test Driven Development). To avoid ambiguity, TDD refers specifically to UTDD (Unit Test Driven Development).
What is a TDD
In the past, it was one-sided to think that TDD = XP’s test-first principle + refactoring, that TDD is only to promote the writing of code through unit testing, and then optimize the internal structure of the program through refactoring. It’s easy to think that you just need to write unit tests first to drive high-quality code, but it wasn’t until I read Kent Beck’s book Test-Driven Development and put some practice into it that I finally got a glimpse of what TDD was underneath the iceberg:
Kent Beck: “Test-driven development is not a testing technique. It is an analytical technique, a design technique, and a technique for organizing all development activities.
Analysis techniques: embodied in the analysis of the problem domain, when the problem has not been broken down into actionable tasks, analysis techniques are used, such as requirements analysis, task resolution and task planning, etc. The book “Instantiating Requirements” can give a certain help.
Design techniques: Test drive code design and functional implementation, then drive code redesign and refactoring, improving the code with constant subtle feedback.
Techniques for organizing all development activities: TDD does a good job of organizing testing, development, and refactoring activities, but is not limited to that. For example, the pre-activities for implementing TDD include requirements analysis, task breakdown, and planning activities, which makes TDD very extensible.
The goal of TDD
Kent Beck, in his book Test-Driven Development, says that “code simplicity and usability is what TDD is all about.”
A divide-and-conquer approach to making code simple and usable can be used, achieving usability first and simplicity later.
Available: Ensure code passes automated tests.
Code simplicity: People understand simplicity differently at different stages, but follow the same principles, such as SOLID OOD, Simple Design by Kent Beck, etc.
While there are many factors that prevent us from getting clean code, or even usable code, there is no need to ask too much advice, just adopt the TDD development approach to drive clean and usable code.
The rules of TDD
There are two simple rules to follow during TDD:
- Write new code only when automated tests fail.
- Eliminate duplication of design (remove unnecessary dependencies) and optimize the design structure (gradually make the code generic).
The first rule implies that you only write code that is just good enough to pass a test at a time, and only write new code when the test runs fail. Since the code added is small, problems can be quickly located, ensuring that you follow the pace of small steps. The second rule is to make the sprints more solid, with automated testing supported by refactoring to eliminate the bad smell of code to prevent it from rotting and create a comfortable environment for the rest of the code.
Separation of concerns is another very important principle implicit in these two rules. It means achieving the goal of “usable” code in the coding phase and “clean” code in the refactoring phase, focusing on one thing at a time!!
The slogan of TDD
In short, unrunnable/runnable/refactoring – that’s the watchword for test-driven development and the heart of TDD. In this closed loop, the output of each stage becomes the input of the next stage.
- Unrunnable – Write a unit test that is minimally functional and complete, and make the unit test compile fail.
- Runnable – Write just enough code to pass a test quickly, without much thought, and even in ways that don’t make sense.
- Refactoring – Eliminates the repetitive design introduced in the coding process and optimizes the design structure.
Assuming such a development approach is possible, what is my real motivation for adopting TDD?
Motivation to adopt TDD
- Control anxiety during programming.
It’s interesting to imagine that the more stressed I feel, the less LIKELY I am to take enough tests. Knowing that I wasn’t testing enough added to my stress, because I was worried that THE code I was writing was buggy, and I wasn’t confident enough in the code I was writing, which was a change in mindset. Testing is the developer’s litmus test, turning fear of stress into a chore. With automated testing, you have the opportunity to choose the level of fear.
- The gap between feedback and decision making in the control programming process.
If I do a week of planning, and I quantify it into actionable tasks and write it to a to-do list, and then I use test-driven coding, and I cross off the completed tasks like this, then my goals become very clear, because I know when, I know what to do, I know what’s difficult, You can consciously make adjustments in the context of constant subtle feedback, such as adding new tasks and removing redundant tests; And even more exciting, I know when I can probably finish. Project managers can have a more accurate grasp of the software development schedule.
The overall TDD process
- Think about what I’m going to do, think about how I’m going to test it, and write a little test. Think about the required classes, interfaces, inputs, and outputs.
- Write enough code to make the test fail (it’s better to fail explicitly than to feel vague).
- Write just enough code to pass the test (make sure that any tests you write before also pass).
- Run and observe all tests. If it doesn’t pass, resolve it now, and the error will only fall on the newly added code.
- If there is any repetitive logic or unexplained code, refactoring can eliminate duplication and improve presentation (reduce coupling, increase cohesion).
- Run the tests again to verify that the refactoring introduces any new errors. If it doesn’t, you probably made some mistake during refactoring that needs to be fixed immediately and rerunked until all the tests pass.
- Repeat the steps until you can’t find any more tests that drive you to write new code.
Three strategies to make the test program run:
- Pseudo implementation – You can return a constant or variable and adjust the pseudo implementation until the pseudo implementation becomes an acceptable implementation code.
- Obvious implementation – Just type the implementation code because you already know how to write the implementation code.
- Triangulation – I can use triangulation when I know exactly what the input and output are but don’t know what the design and implementation behind it is. The principle is to start with a simple working example as a reference information source and then pull out the obvious implementation of the test. Details are given in Resources.
The goal of these three rules is to make the code “usable” by typing what we think is the correct code to get the test program through as quickly as possible.
The difficulties of TDD
- Lack of awareness of software quality
- Without some degree of programming ability, it is difficult to design structures and code with high cohesion, low coupling and clear intent.
- Lacking the ability to analyze requirements and break down and plan tasks, it’s easy to get thrown off track before you even start TDD.
- Lack of suitable test environment and test specification.
- Test-first habits are hard to develop.
- Unskilled reconstruction techniques.
TDD doubt
- They say run in small steps, but how small are they?
In both test procedures covering the scope of the refactoring intermediate steps of TDD advice is to use as far as possible little pace (test can’t break up, tiny refactoring), but no compulsory must according to this step, the pace of different people can be different, can be in practice constantly looking for suitable for their own pace, but the premise must be small as far as possible.
- What needs to be tested? What doesn’t need testing?
Depending on your experience and how confident you are in your code, this is not the case for people who don’t write tests and still feel very confident in their code. If some code feels confident that it can run and refactor without testing, such as most set Gets, you can do without testing. On the other hand, if removing it makes you feel uncomfortable, you need to consider adding it.
- Why do I need to follow the unrunnable/runnable/refactorable order and not the other order?
This question is also hard for Test-Driven Development author Kent Beck to prove because no one has actually done the statistics, so he doesn’t deny that there might be some better sequential design.
- Why only write “usable” code each time in the runnable phase?
Because you want to get your tests up and running as quickly as possible, you can reduce the feedback cycle from the system, and if you can get feedback from the system quickly and consistently, you can keep up the pace of sprints. If you can achieve a good design in a short period of time, and write elegant and concise code, you should use the best design at the beginning of TDD, because it will be more efficient.
- Is TDD a silver bullet?
TDD is not a silver bullet. When you encounter a problem, you need to find out what the core pain point is, and then apply the remedy to the problem.
Unit testing
, unlike the ATDD UTDD aimed at developers, so UTDD main concern here is the quality of the software inside attribute, if the external quality of software embodied in the “defect” and “defects” indicators, such as the internal quality attributes of software embodied in the code “testable”, “readability” and “scalability”, These are the pursuits of almost every software development engineer. As one of the products of TDD, automated “unit testing” is often used as the “foundation” of software quality assurance in order to control the internal quality attributes of software.
In computer programming, Unit Testing, usually written by software developers to ensure that the code they have written matches the requirements of the software and complies with the development goals, is the Testing of the correctness of the program module (the smallest Unit of software design).
Each ideal test case is independent of the others; To isolate modules while testing, dummy programs such as STUbs, mock, or fake are often used for testing.
Typically, programmers will conduct at least one unit test for every change they make to a program, and it is likely that many unit tests will be performed before and after the program is written to verify that it is working as required by the software specification.
As you can see from the Wikipedia description, unit tests have the following characteristics
- Written by developers.
- Test functions/methods (TDD is more granular).
- Used to verify the correctness of code.
- Unit tests are run before and after coding and when code is modified.
- Frequently use a test sock program such as STUbs, mock, or fake to ensure that each unit test is independent of each other (orthogonal)
Here is a brief analysis of unit testing from my personal point of view, but the understanding of “unit testing”, or its place, is not clear enough, so I use the “test pyramid” model to help me understand “unit testing” from a higher perspective.
Test the Pyramids
Above the “pyramid” model of two dimensions according to the speed and cost of different stages of the test work very intuitive visualization, you can see the unit test, is located at the base of the pyramid “test” the most obvious “unit tests” relative to the other at different stages of testing, with fast speed (efficiency), the advantage of low cost (maintenance), At the same time, it is also the support of the upper testing work, reflecting the importance of “unit testing”.
conclusion
The article theoretically summarizes the overall picture of TDD and some strategies in TDD practice, including the difficulties and questions of TDD. The word “feedback” is mentioned many times because TDD is a technology that introduces a lot of low-level feedback (thanks to automated testing), which makes it possible to see the results of actions quickly. Using TDD, It will learn how to craft our code in a hands-on way, resulting in a stable object-oriented design, maintainable, and high-quality system.
subsequent
Only by integrating knowledge and action, guiding practice through theory, constantly summing up experience in practice and constantly verifying one’s own knowledge can one have a deeper and more correct understanding of TDD. The next few articles are planned to demonstrate how TDD can be used to solve some real case studies in order to improve your TDD skills.
Literature reference
- trigonometry
- Thoughts on promoting TDD — Zhang Yi
- TDD(Test Driven Development) training record – break the Wolf
Welcome to follow my wechat subscription number, I will continue to output more technical articles, I hope we can learn from each other.