1. Write unit tests for Unit Tests
Recently, I have done" Program Team members write unit tests in project development.
The survey results show:
1. Almost no strict implementation of TDD (, TDD) in the project ).
2. Write unit tests for most business methods and ensure that the methods pass the tests, accounting for 16.6%.
3. Occasionally write unit tests. In general, no unit tests are written, accounting for 58.3%.
4. Write unit tests to cope with project checks, but there is no guarantee that the methods have passed the tests, accounting for 8.3%.
5. Never write unit tests, accounting for 16.6%.
Although the results of the survey have a certain degree of one-sidedness, the proportion of 58.3% is indeed high. At the same time, the 16.6%-person layer of unit tests never compiled reflects the situation of domestic programmers writing unit tests, few programmers can write unit tests carefully. So why did programmers not write unit tests? Based on the many discussions I have participated in, there are several main reasons why programmers do not write unit tests:
1. In order to complete the coding task, there is not enough time to write unit tests. Writing unit tests may result in the failure to complete coding tasks on time and delay the project progress.
2. unit testing is a waste of time because of its low value.
3. the business logic is relatively simple and it is not worth writing unit tests.
4. I don't know how to write unit tests.
5. The project is not required, so it is not written.
6. Write unit tests as much as possible in the early stage of the project, but the more you get out of control in the later stage of the project.
Testing is often a very boring project activity for programmers. What does testing bring to us? Understanding these is very important. testing cannot ensure that a program is completely correct, but testing can enhance our confidence in program integrity, testing can convince us that the program has done what we expect it to do. Tests enable us to detect program bugs and deficiencies as early as possible.
The longer a bug is hidden, the higher the cost of fixing it. A large amount of research data has been cited in the quick software development book, pointing out that the price of modifying a bug is 10 times the price of modifying it when a bug is generated.
Here, we need to focus on unit testing. Unit testing is a method-Level Test, and unit testing is also the most fine-grained test. Each method used to test a class has met the functional requirements of the method.
In the modern software development process, both XP and RUP place great importance on unit testing. Unit testing has been taken as an important development activity throughout the entire development cycle. Especially in the modern software development process, there is a methodology of frequent integration and progressive submission. Therefore, a very good unit test theory and practice are summarized.
2. WritingCodeWrite unit tests first, that is, test first.
Unit testing is a part of the code, and all the Code must have unit tests and pass the tests (such as the excellent open-source projects such as spring have made very good examples in this regard ).
Modify the unit test before modifying the code, and make it pass the test.
Writing unit tests before writing code brings many benefits.
Before writing code, write unit tests first. Before writing code, you do not need to write unit tests for all classes at once. This requires granular control. The maximum granularity should be controlled at the class level. The most appropriate granularity is to control at the method level. First, write the test code for a method, and then write the implementation code for the method until it passes the test and then write the test code for another method. Unit Testing is already a contract specification, which regulates what the method should do and what to implement. Testing code is much more valuable than Requirement documents that are hard to read and will not be updated in a timely manner.
Test first to encourage understanding of requirements. If you do not understand the requirements, you cannot write the test code. Of course, you cannot write a good implementation code.
The test code is more valuable than other documents. The implementation code also changes when the requirement changes. The Requirement documents and design documents are often not updated in a timely manner. The test code is more valuable than those expired documents.
Test first, you can compile the test code with maximum coverage. If you write the test code after writing the implementation code of the method, the developer always writes the test code with the correct path. It is difficult to analyze other branch logics comprehensively.
If we use test first, we will automatically complete the writing test for all classes. Writing and testing for all classes will bring you many benefits.
We can use automated testing to test all classes, especially systems built on a daily basis. It gives us peace of mind to add new functions for classes or methods. We can easily modify the test code and verify that the modified Code is useful. This allows us to refactor and optimize code with confidence.
Refactoring and design optimization are usually associated with multiple classes and multiple methods. If we write tests for all classes, we can easily test whether our modifications are correct after refactoring the code.
Writing tests for all classes makes it easy to modify bugs. After receiving a bug report, we always modify the test code first, and then modify the implementation code to make the test successful. This will not cause new problems because of modifying a problem.
A good unit test strategy enhances our confidence in the program, reduces the bug generation and latency, and reduces the bug modification cost.
Unit testing is not a certain life cycle of the project development cycle. It runs through the entire life cycle of the project and is a very important daily development activity.
3. Why do programmers refuse to write unit tests?
We already know how important unit testing is. Why do programmers still not write unit tests? Why do programmers always have a reason to refuse to write unit tests?
1. Writing unit tests increases the workload and delays the project progress?
This is the most reason why programmers refuse to write unit tests during many discussions and surveys. "To complete coding tasks, there is not enough time to write unit tests. Writing Unit Tests will lead to the failure to complete coding tasks on time and delay the project progress ". Is that true?
Software has a special life cycle, and software development is also special.
First, we need to provide users with at least one product that can run. It cannot be a bunch of dead code that cannot be run and is full of "bad smell. Only codes that can run and meet customer needs are truly useful codes. Then, the Code becomes a product.
Many programmers only focus on the completion time of code writing, while the time for code debugging, integration, modification, and maintenance is almost the same.
If there is no unit test, the development activity will be like this.
Take a web application development as an example. The process is like this: the Business Code is compiled, packaged, and released to the server for functional testing. If a problem occurs, modify the code and then package it ...... This loop.
No Web programmer is familiar with this development scenario. The time for packaging, publishing, and functional testing is usually more than 10 times that of coding. By integrating the system to discover program bugs, it is often difficult for us to accurately locate the bugs at once. The error message provided by the application server is very limited for us.
What kind of development scenario would happen if I wrote a unit test for each class and passed each method test?
Write test code Write Business Code run test method modify code so that all the classes passed the test are tested, packaged, and released to the server for Function Testing discover bugs modify test code modify Business Code test passed and then package...... This loop.
From the above process, we need to spend more coding time. Because you need to write test code for each service class. However, it does not cause us to spend more time on the whole. We can simply run the test method in the IDE environment.
Before the code is packaged and released, we have ensured the correctness of the Business Code. When we integrate all tested code into the application server, there is much less chance of errors. When a bug is detected after the integration test, we always modify the test class first. Ensure that all classes have passed the test before integration. In this way, the functional testing time is reduced by an order of magnitude, so the total time spent is much less than no unit test.
In addition, if there is no unit test, some low-level errors may often occur, such as spelling errors and NULL pointer exceptions. Because of a small spelling mistake, you need to repackage and release it once. If you have a unit test, you can avoid these low-level errors.
If there is no unit test, when we integrate code into the application server and discover errors, we often rely more on our own experience to determine where the problem is. It is only luck for inexperienced programmers. This is like walking with a blind man. If each class has a unit test, there is no need for such pain.
This reminds me of my network system. At that time, the local area network used a ring network, and there was no current switch to form a star network. The transmission network of the ring network uses a coaxial cable. All nodes in the network are on a trunk line, and a resistor is added to both ends of the network to form a ring (for example ).
The biggest drawback of a ring network is that when any node has a fixed fault, the entire network cannot be connected. It is very troublesome to maintain this network. The "cut sausage" method is usually used in many ways. Take down the last resistor, connect it to the end of the network node of the second computer, and check whether the two wires can be connected. After the connection, the resistor is removed to the end of the network node of the third computer and connected to the third computer. In this way, check the entire network line in sequence.
Later, star networks were developed and widely used in local area networks. There is a vswitch, and each computer is connected to the vswitch. Any node network failure does not affect other nodes. It is very convenient to check. Code without unit tests is like a ring network, and code with tests is like a star network.
Secondly, it is possible that the code we wrote for the first time is no problem, but some of the Class Code was modified after the demand was changed and published to the application server for testing, the content to be modified has passed the test. However, the Code changes of some classes make other classes unable to work normally. This kind of bug is often hidden very deeply, because it will not appear as long as it is not touched. It may be discovered by business personnel only after the program is released to the production environment. If each class has a test code, we can run all the test code before packaging, and we can easily find the connection errors caused by code modifications.
Finally, the closer the bug is to be generated, the easier it will be to fix the bug. The farther the bug is generated, the more expensive it will be to fix the bug. Let's assume that we integrate the code written one week (or even longer) ago. When we find the problem, we forget a lot of important implementation details, so it is difficult to modify it.
Writing unit tests does not increase the burden on programmers, but increases the programmer's confidence in the program and greatly reduces the time for repeated packaging, release, and error correction. It takes much more time than writing unit tests. Writing Unit Tests makes it easier and easier for you to modify code and add features to speed up project development.
Why do we always think that writing unit tests will delay the project progress? Rather than struggling, try a good practice.
2. Simple business logic, not worth writing Unit Tests
Programmers are smart, and programmers always think they are smart. Some classes with simple business logic do not need to write unit tests. We must acknowledge that demand is changing and we must have the courage to accept it. Another purpose of writing unit tests is to embrace changes, rather than reject changes. Writing Unit Tests improves our confidence in the program.
In agile software development, the code is owned by all members of the project team, and anyone in the project team can modify any code file. Whenever I want to modify the code written by someone else, I always hope that the unit test code of a program will disappoint me very much. Generally, I have to spend a lot of effort to guess the author's original intent. Maybe you will say, "You can see the requirement document! Won't you go to the comment ?". However, when the requirement document completes its mission, the developer throws it aside and the document always expires. Few project teams can make the requirements consistent with the latest implementation code. Therefore, reading an expired document is of no value. Similarly, keeping up-to-date with annotations is still the biggest problem, and the information that annotations can provide is very limited. So what I need most is to check the test code. The test code best reflects the latest function contract of the method. Unit Tests written by code writers are more comprehensive and accurate than unit tests written by others.
A lot of problems occur in some code that we think is simple. Unless it is like the getter and setter methods of a JavaBean, because these methods can be automatically generated by IDE code, and there is no need to write a test for it.
In project development, we often need to optimize code and improve our design through refactoring. After code refactoring, how can we ensure that the Code is still normal? That is to test all the modified Code. If the test passes, the reconstruction is correct.
We cannot avoid code maintenance issues. Code maintenance includes bug fixing and adding features. The maintenance work may be a long time before the code writing is completed. How can I ensure that the modified Code is still correct and there is no hidden danger when I modify the code by modifying a bug or adding a new function?
Maybe you will say that you should release it to the server for testing. I have encountered more serious problems due to maintenance. A system has been running normally in the production environment for a long time. One day, the business staff asked to modify a function. The author implemented the function to be modified according to the business requirements. The business also tested the modified function and then released it to the production environment. Two weeks after the program was issued, it reported a very serious production problem. Previously, the normal operation of the function suddenly encountered a problem, resulting in a large number of production data errors. This problem is very fatal and can only be temporarily disabled.
Finally, I found out that the error module is associated with the code modified last time, and the module failed to be modified at the same time. If I can run all the test classes after modifying the code, the test will certainly fail. In this way, the hidden programs with such serious errors will not be delivered to the production environment.
Let's see how integration is implemented without writing unit tests. If some results are inconsistent with what we expected, we may add many print statements in the program and monitor the program running process through the console. Using the print statement does not guarantee the correctness of our program. The best case is that it can only ensure a correct path, but not other branches. In addition, when too much print statement information is on the console, we will not see the desired information-the console information is limited. During development and testing, it is acceptable to print debugging information on the console. However, if debugging information is displayed on the console in the production environment, it is absolutely unacceptable. We often forget to delete the debug print statement in time, thus affecting program performance. The most important thing is that the print statement does not guarantee the correctness of the program, nor can it save you time for development. It will only have a negative impact on you.
3. I don't know how to write unit tests.
If you believe in the value of unit testing, learning how to write unit testing will ultimately benefit you.
Taking Java Development as an example, unit test components such as JUnit are very easy to learn and use. Similar unit test components are available in other languages. Believe that this will be simple and can bring value to you. I have seen many programmers write unit tests, but the unit tests I have written do not play their due role at all. This is also related to the failure to know how to write unit tests. Therefore, we should master some basic principles for writing unit tests:
• Writing tests: although we say that unit tests are written for all substitute classes, the setter or getter Method for Testing Javabean is nothing more than self-seeking. Writing such a test is a waste of time and increases the maintenance difficulty.
• Learn To Use assertions: Assertions allow us to set an expectation for a method. When the method execution result is different from the expected value, the test component reports that the test fails. I have seen some projects in unit testing, instead of using assertions, but writing a println tool class by myself. You can print the detailed member information and Set details of the class in the console in detail.
Use this printing tool class in unit testing to print the output results. This looks very good. However, this method should not be used to compile unit tests and use the print tool class. The programmer needs to observe the program execution results from the console. When a large amount of output information is displayed, the console information cannot be displayed. Therefore, we cannot provide more information. Therefore, this method cannot be used for automated testing.
The use of the print tool class creates a false image. The test report is always successful! If assertions are used, when the execution result of the method is different from the expected value we set, the test failure is reported in detail.
The print tool is used to replace assertions, resulting in inadequate testing. Only a test with low test coverage will be written. We need a full test.
• Maximize test coverage: In addition to testing a correct path, we also need to test each branch logic of the method. You need to write as much test program code as possible for testing. Write a full test.
• Avoid repeated test code: The test class is also very important, just like the application code. The more repeated code the test class contains, the more errors the test class has. The more coding we need.
• Do not rely on the execution sequence of the Test Method: Using JUnit for unit testing cannot ensure that the test method is executed in the order of our intent. When a test class has multiple test methods, we cannot make a test method run after a test to succeed. JUnit cannot guarantee this for us, and we cannot rely on the execution sequence of the test method.
• For interface testing: we have an OO design principle for "interface programming. We also need to test the interface for testing. That is to say, when writing a unit test, the test object always uses an interface instead of a specific class.
4. The project has no requirements, so no unit test is written.
Indeed, in many projects, the team does not require us to write unit tests for each class, but rather requires us to write a lot of complicated documents. As programmers, we need to understand that programmers are the biggest beneficiaries of unit testing.
This is not about the project manager, nor about QA, but about the programmer, because unit testing is part of the program code. Unit testing is the best and most valuable document and should be delivered to the customer together with the code.
Unit test code is not a bureaucratic or rigid document. It is vivid and the most useful document for programmers. Unit Testing can improve the programmer's confidence in the program and be able to use the well-developed design principles: "programming for interfaces, not specific classes ". To perform unit tests, we need to make the class independent of its dependent objects (using mock or stub) for testing. This forces us to develop good programming habits.
Unit testing is a guarantee to improve our design. As a good programmer, code and design are frequently optimized, so refactoring is often performed. A good programmer cannot tolerate "bad smell" code, and unit testing is the confidence guarantee for us to refactor.
Unit testing is a daily development activity that runs throughout the entire project lifecycle. Being a responsible programmer is always responsible for the quality of your code. Do you often improve your design and make it easy for others to use and modify your code.
Writing unit tests for all classes should be the qualities a programmer should possess. There are no requirements for the project and it should not be the reason for not writing unit tests.
5. Why is unit testing more difficult to carry out later in the project?
In the early stages of many projects, most programmers can consciously write unit tests. As the project progresses, the task increases, and the delivery time is getting closer and closer, the risk of failing to finish the project on time is getting greater and greater, and unit testing is often a victim. The project manager does not pay much attention to the progress, and the programmer does not write unit tests for the code because of the coding pressure and oversight.
All of my projects have such a bad situation. In the later stage of the project, no more than 15% of the entire project team will be able to stick to the unit test program.
To catch up with the progress, the vast majority of programmers submit code that has not passed any tests to the version server, and the Project Manager will not ask any more and accept the code as per the order. The result is that in the later stages, integration takes more and more time, and several technical backbone staff have to work overtime day and night to integrate the system. After the integration is completed, the bug report increases by an order of magnitude when it is delivered to the tester for testing. Programmers modify bugs day and night, and many bugs are hidden deeper, lurking in the production environment. In projects, more and more people are losing confidence in the project. Everyone is complaining about the countless bugs, fixing a bug, and reporting more bugs.
Bugs are being modified every day, but more bugs are reported every day. As a result, some people wanted to leave, while others asked for leave. At the end of the project, everyone knows that the project is too bad and many errors have not been tested yet. Hurry and escape from the project team! Half of the people fell ill, or lost confidence in project maintenance.
Why? Do you know the importance of the test? In the initial stage of the project, we should publicize the importance of unit testing.
Have you done any related training? When the project starts, some related training is required to teach team members the most basic unit testing skills.
Have you done risk prevention? The more senior programmers are, the more they refuse to write unit tests. They always have too many reasons to refuse to write unit tests. These "stubborn" old programmers are often responsible for writing core code. We know the "20-80 law. 80% errors occur in the code of 20%, and the most serious errors often occur in the code of the "old birds. Is there any risk prevention in advance to persuade them to write unit tests.
Is there any basic work related to the test. Is there any test base class for different types of programs that makes writing and testing a very simple task. Some Code depends on specific environments, such as EJB access, JNDI access, and Web applications dependent on servlet APIs. However, it is very difficult to test these programs. You should write some test base classes and test stub so that these programs can perform unit tests just like normal programs in a specific environment. This allows common programmers to easily write test code for program testing.
You can perform daily build and test coverage check. Code that has not passed the test cannot be placed on the version server. Check the test coverage rate.
In modern software development, testing is no longer an independent life cycle. Unit testing is a development activity that is synchronized with coding. Unit Testing can improve the programmer's confidence in the program, ensure the quality of the program, speed up software development, and make the program easy to maintain. No matter whether the test is performed first or before the test is performed, no unit test is required.
The weak find reasons, and the strong find a way! Have you conducted a unit test today?
Original article address