Why don't programmers write unit tests?

Source: Internet
Author: User
The note once conducted a survey on "unit tests written by programmers in project development. Survey results: 1. strictly execute tdd in the project. 2. Write unit tests for most business methods and ensure that the method test passes. 16.6%. Write unit tests occasionally. Generally, do not write them. 58.3%. Write unit tests to cope with project checks, but there is no guarantee that the method passes the tests. 8.3%. Never write unit tests. 16.6% of the survey results are not very accurate because of its limitations or one-sided nature. It can also basically reflect the situation of programmers writing unit tests in China. Few programmers can write unit tests carefully. So what is the reason? Based on the many discussions I have participated in, there are mainly the following 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 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. There are no requirements for the project, so do not write it. 6. Write unit tests as much as possible in the early stage of the project, but the more you get into the later stage of the project, the more out of control. 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 the program. Testing can convince us that the program has done what we expect it to do. The test allows us to discover a program bug 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 referenced in quick software development. Note: The final cost of modifying a bug is 10 times the cost of modifying it when the 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. A good unit test theory and practice have been summarized: before writing code, write unit test, that is, test first unit test is a part of the code, and all code must have unit test, and make the test pass. (For example, this is an excellent example in spring open-source projects.) before modifying the code, modify the unit test and make it pass the test. Writing unit tests before writing code brings many benefits: writing unit tests before writing code, it is not necessary to write unit tests for all classes at one time before writing code. This requires a granularity. 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 far 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. 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 adopt test first, we will automatically complete the practice of writing and testing for all classes. Writing and testing for all classes will bring you a lot of benefits: We can use automated testing to test all classes well, especially for systems built on a daily basis. We can safely add new functions for classes or methods. We can easily modify the test code and verify that the modified Code is useful. It gives us peace of mind to refactor and optimize the code. Refactoring and design optimization are usually associated with multiple classes and multiple methods. If we write tests for all the classes, we can easily test whether our modifications are correct after refactoring the code. Writing tests for all classes makes it easy for us 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. Good unit test strategies increase our confidence in the program and reduce the generation of bugs and the latency of bugs. Reduce 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. 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? I. 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 unfeasible and smelly dumb code. 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: After the Business Code is compiled, choose package> Publish to Server> test functions> discover problems> modify code> package again ...... This loop. No Web programmer is familiar with this development scenario. It is often packaged, released, and functional testing takes more than 10 times as long as code is written. 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? Compile the test code-> compile the Business Code-> run the test method-> modify the code to pass the test-> all classes pass the test-> package-> Publish to the server-> perform the function test-> detect bug-> modify test code-> modify Business Code-> test passed-> package again... 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, this 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, such as spelling errors and NULL pointer exceptions, often occur. Because of a small spelling mistake, you need to re-package 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. It's like a blind man walking, with a black eye. 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. 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 modification of some classes causes other classes to fail 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. Third, the closer a bug is to be generated, the easier it is to fix it. The farther a bug is generated, the more expensive it is to fix it. 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 will not increase the programmer's burden, but increase the programmer's confidence in the program, greatly reducing the time for repeated packaging, publishing, 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 functions 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. the business logic is simple, and it is not worth writing unit test programmers. 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 collectively owned, and anyone in the project team can modify any code file. Whenever I want to modify the code written by someone else, I always wish to have the unit test code of the program, which often disappoint me very much. Generally, I have to spend a lot of effort to guess the original intention of the original author. 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 correct? 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 many print statement information is on the console, we will not see what we want to see. 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 tests, learning how to write unit tests 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. However, I have seen many programmers write unit tests that do not play their due role. This is also related to having no idea how to write unit tests. Therefore, we should master some basic principles for writing unit tests: why should we write tests? Although we say that unit tests are written for all generations, however, the setter or getter Method for Testing Javabean is not a self-seeking headache. Writing such a test is a waste of time. It also increases the difficulty of maintenance. Learn to use assertions: Assertions allow us to set an expectation for the 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 tests not using assertions, but writing a println tool class by myself. You can print the detailed member information of the class in the console in detail, and set details. 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 many test program logic tests as possible. 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 we intend. 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 the "for interface programming" OO design principles. 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. There are no requirements for projects, so it is true that in many projects, the team does not require programmers to write unit tests for each class. Instead, we are required 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 a project manager, nor a QA task, but a programmer's own business. Unit testing is a 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, 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. Unit testing is the confidence guarantee for restructuring. 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 unattended access. All my projects are happening in 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 the project, more and more people are losing confidence in the project. Everyone is complaining about 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. Let's know the law of 20-80. 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. 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. Find the reason for failure, and find the method for success! Have you conducted a unit test today?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.