How to perform Unit Testing

Source: Internet
Author: User
Tags call back
How to perform Unit Testing
Author: Qiao yuan [2005/02/16]
Abstract:Unit testing is the basis of software testing. This article describes in detail the two steps of unit testing: Manual Static check and dynamic execution tracing, the work items to be executed, and related strategies and methods. By describing these two steps, the author injects many years of unit test experience and testing theory into the full text.
Keywords:Unit Testing, manual inspection, white box testing, test cases, tracking and debugging
1 Overview
Unit testing is a test of the correctness of the program module, the smallest unit of software design. The purpose is to discover possible internal errors in each program module.
Unit testing is also a basic responsibility of programmers. programmers must be conscientious and responsible for the code they write. This is also one of the basic professional qualities of programmers. At the same time, the unit test capability is also a basic capability of programmers. The level of ability directly affects the working efficiency of programmers and the quality of software.
Unit Testing in the coding process has the smallest cost, but the return is extremely generous. In the coding process, consider the test problem and get better code, because at this time you have the clearest understanding of what the code should do. If you do not do this, wait until a module crashes and you may have forgotten how the code works. Even under intense work pressure, it takes a lot of time to figure it out again. Further, the corrections made in this way are often less thorough and more fragile, because the understanding you call back may be less complete.
Generally, qualified codes must be accurate, clear, normative, consistent, and efficient (sorted by priority ).
1. correctness means that the Code logic must be correct and can implement the expected functions.
2. Clarity means that the Code must be concise and easy to understand, and the annotations are accurate and unambiguous.
3. standardization means that the Code must comply with the common norms defined by the enterprise or department, including naming rules and code styles.
4. Consistency means that the Code must be named (for example, variables with the same function should use the same identifier as much as possible) and the style should be consistent.
5. Efficiency means that the Code should not only meet the above requirements, but also reduce the code execution time as much as possible.
Unit 2 Test Procedure
The unit test after code writing is divided into two steps: Manual Static check and dynamic execution tracking.
Manual Static check is the first step in testing. This phase ensures the logic correctness of the code algorithm (try to discover the logic errors of the Code through manual check), clarity, standardization, consistency, and algorithm efficiency. And try to discover errors not found in the program.
The second step is to design a test case and execute the program to be tested to track and compare the actual results with the expected results to find errors. Experience shows that Manual Static checks can effectively detect 30% to 70% logical design and coding errors. However, there are still a large number of hidden errors in the code that cannot be detected through visual inspection. Therefore, you must follow the tracing debugging method for careful analysis to capture them. Therefore, the dynamic tracking debugging method has become the focus and difficulty of unit testing.
3 manual check
The following project activities are usually required during the manual check phase:
First, check the logic correctness of the algorithm; Determine whether the written code algorithm and data structure definition (such as queue and stack) have implemented the functions required by the module or method.
Second, check the correctness of the module interface, determine whether the number of formal parameters, data types, and order are correct, and determine whether the return value type and return value are correct.
3. Check whether the input parameter is correct. If no, check whether the input parameter is correct. Otherwise, add the parameter correctness check. Experience shows that the absence of code for parameter correctness check is one of the main causes of unstable software systems.
4. Call other method interfaces to check whether the real parameter type is correct, whether the input parameter value is correct, and whether the number is correct, especially the method with polymorphism. Whether the returned value is correct or not. Do you misunderstand the meaning indicated by the returned value. We recommend that you use the explicit wet code to check the correctness of the returned values of each called method. If an exception or error occurs in the called method, you should give feedback and add appropriate error handling code.
Fifth, error handling; the module code must be able to anticipate error conditions and set appropriate error handling so that once a program error occurs, the program can be rescheduled, to ensure the correctness of its logic, such error handling should be part of the module function. If one of the following conditions occurs, it indicates that the module's error handling function contains errors or defects: the error description is difficult to understand; the error description is insufficient to locate the error and determine the cause of the error; the displayed error information is inconsistent with the actual error cause; the error conditions are not correctly handled; Before the error is handled, the error conditions have caused system intervention.
Sixth, ensure the correctness of expressions and SQL statements, and check the correctness of the syntax and logic of the compiled SQL statements. The expressions should not include ambiguity. For expressions or operator priorities that are prone to ambiguity (such as, =, &, ||, ++, and) you can use the "()" operator to avoid ambiguity. This ensures the correctness and reliability of the code and improves the readability of the Code.
7. Check whether constants or global variables are correctly used; Determine the values, values, and Data Types of constants or global variables used; ensure the consistency of each constant reference with its values, values, and types.
Eighth, it indicates the standard consistency of the definition of the operator. It ensures that the variable name can be known and concise, but should not be too long or too short, standardized, easy to remember, it is best to be able to spell. Make sure that the same token is used to represent the same function. Do not use the same token to represent different functions. Do not use the same token to represent different functions.
9. Consistency and standardization of the program style. The code must comply with the enterprise specifications and ensure that the Code style of all members is consistent, standardized, and neat. For example, to loop the array, do not use the subscript variable from bottom to top (for example: for (I = 0; I ++; I <10 )), later, we will use the top-down mode (for example, for (I = 10; I --; I> 0). We should try to use the unified method, or use the unified bottom-up mode, or unified from top to bottom. We recommend that you use the for loop and while loop instead of the do {} while loop.
10. Check whether the mysterious number used in the program is defined by a symbol. Mysterious numbers include constants, array sizes, character locations, conversion factors, and other numeric values written in text in the program. In the program source code, a number with the original form does not provide any indicative information about its importance or function, which also makes it difficult for the program to understand and modify. This type of mysterious number must be represented by a corresponding scalar. If this number may be used throughout the system, be sure to define it as a global constant; if this mysterious number is used in a class, it can be defined as the attribute of the class ), if this mysterious number appears in only one method, be sure to define it as a local variable or constant.
11th. Check whether the code can be optimized and whether the algorithm efficiency is the highest. For example, whether SQL statements can be optimized, whether one SQL statement can be used to replace Multiple SQL statements in the program, whether the loop is necessary, and whether the statements in the loop can be extracted out of the loop.
12th. Check whether your program is clear, concise, and easy to understand. Note: lengthy programs are not necessarily clear.
13th. Check whether the internal comments of the method are complete; whether the comments are clear and concise; whether the code functions are correctly reflected; the comments with errors are worse than those without comments; and whether redundant comments are made; there is no need to comment out the code that is easy to understand.
14th. Check whether the annotation document is complete, and whether the annotations for packages, classes, attributes, method functions, parameters, and return values are correct and easy to understand; whether a parameter is commented out, whether the parameter type is correct, and whether the parameter's limit value is correct. Especially for comments about mysterious values in the form parameters and return values, such as: type parameters should indicate what 1 represents, 2 represents, and 3 represents. Comments to the returned result set should contain the fields, field types, and field sequence in the result set.
4. Dynamic execution tracking
Dynamic Testing is usually divided into black box testing and white box testing. Black box testing refers to the functional design specifications of a product. You can perform tests to verify that each implemented function meets the requirements. White-box testing refers to the internal working process of a known product. It can be tested to verify whether each internal operation meets the design specifications and whether all internal components have been checked.
For unit tests, the white box testing method should be used to perform internal tracking and inspection tests for each module. For unit white box testing, the program module should be checked as follows:
1. test all independent execution paths in the module at least once;
2. Perform the logical determination at least once in two cases: true and false;
3. Execute the loop body within the loop boundary and running boundary;
4. test the effectiveness of internal data.
Unit white box tracking testing usually requires the following three tasks:
1. design test cases;
2. design the test module;
3. Tracking and debugging.
4.1 Test Case Design
Generally, dynamic tracing debugging is performed in the encoding phase. After the source program is statically manually checked, you can start the unit test case design. Use the design document to design multiple test cases that can verify program functions and identify program errors.
4.1.1 basic design principles for test cases
The basic principles for designing test cases are:
1. A good test case is that no errors have been found;
2. the test case should consist of the test input data and the expected output result;
3. Reasonable input conditions and unreasonable input conditions should be included in the test case design.
4.1.2 white-box test case design
White-box test cases are generally designed using the logical coverage method and the basic path method.
I. logic coverage Method
Logic coverage is a test case design technology based on the internal logic structure of the program. This method requires the tester to have a clear understanding of the logical structure of the program. Logical coverage can be divided into statement coverage, decision coverage, condition coverage, Decision-condition coverage, condition combination coverage, and path coverage.
1. Statement overwrite is to design several test cases to run the tested program so that each executable statement can be executed at least once.
2. Decision coverage is to design several test cases to run the tested program so that each of the true branches and false branches in the program can go through at least once.
3. Conditional coverage is to design several test cases to run the tested program so that the values of each criterion in the program can be executed at least once.
4. Decision-condition coverage is to design enough test cases so that all possible values of each condition in the judgment are executed at least once, and all possible judgment results of each judgment are also executed at least once.
5. Condition combination coverage is to design enough test cases to run the tested program, so that all possible conditions for each judgment can be combined at least once.
6. path testing is to design enough test cases to cover all possible paths in the program.
Each method has its own advantages and disadvantages. The relationship between the six methods is as follows:

Figure 1
Generally, when designing test cases, we should select the coverage method based on the complexity of the Code module. The complexity of the general code is directly proportional to the complexity of the test case design. Therefore, the designer must be single and highly cohesive in the module or method functions to make the method or function code as simple as possible. This will greatly improve the ease of test case design, improve the coverage of test cases.
Ii. Basic Path Method
The basic path test method is based on the control flow diagram of the program. By analyzing the loop complexity of the control structure, the basic executable path set is exported to design the test case method. The designed test case should ensure that each executable statement of the program in the test should be executed at least once. The basic path test includes the following five aspects:
1. control flow diagram of a program: A graphical method that describes the control flow of a program.
2. complexity of the program environment: McCabe complexity measurement; from the loop complexity of the program, you can export the number of independent paths in the basic path set of the program, this is the upper limit of the number of test cases required for each executable statement in the program to be executed at least sequentially.
3. Export test cases.
4. Prepare test cases to ensure the execution of each path in the basic path set.
5. Graphic matrix: a software tool that assists in basic path testing. It can be used to automatically determine a basic path set.
In addition to meeting the selected coverage (or coverage criteria), the selection of test cases also requires the use of common design methods such as the Boundary Value Analysis Method and the error inference method. The boundary value analysis method is used to design reasonable and unreasonable input conditions. The condition boundary test case should include the input parameter boundary and condition boundary (if, while, for, switch, SQL WHERE clause ). The error inference method lists all possible errors and special circumstances that are prone to errors in the program, and selects test cases based on them; many common and suspected errors can be found in the coding and unit test phases. These errors should be tested with emphasis and corresponding test cases should be designed.
4.1.3 unit test plan form
When designing test cases, you can refer to the following table to develop a test plan for each class (or module or package. Table 1 is the header of the test plan for each class (or module or package), which indicates that the test plan is for that module and related files. Table 2 is a sub-table corresponding to a module test case specified in Table 1. Each test case can have a sub-table. The sub-table of unit test results is left as the actual result when the test case is executed.
Subsystem name. packagename. javaclassname
Unit Test Plan
Identifier Format:
"Subsystem name. jsp_filename (including directory middle use/separate )"
Or
"Subsystem name. packagename. javaclassname"
Component functions For example, the component completes the "add post" function.
Design file names for overview/details For example, the detailed design manual of Version 1.1 announcement
Physical file name Jsp_filename (including directories );
Packagename. javaclassname

Table 1
Unit test item 001
The following table lists the sub-tables corresponding to "subsystem name. packagename. javaclassname" in the preceding table. A sub-table is used for each test case:

No. . 001 Note: The ". No." part starts from 001 to 999.
Program designer For example, GE Zhichun
Tester For example, GE Zhichun
Purpose For example, the error logic input test
Test Description For example, for public int fun3 (string P1, int P2) input check, if p1 = NULL, the program checks, should be recorded in the system logfile, return-1;
Input expectation P1 = NULL
Expected function processing description Logfile has one more record, with the return-1 method;
Output expectation Return-1
Unit Test Results
Actual input data P1 = NULL
Actual handling description The program does not perform the verification of P1 = NULL, but does not return-1 in time, but runs the p1.aaa () method with a null pointer exception.
Actual output No logfile file is written;
Test conclusion Normal/abnormal

Table 2
4.2 Test Design
A module or method is not an independent program. When considering testing it, you must consider its connection with the outside world, use auxiliary modules to simulate other modules associated with the tested modules. These auxiliary modules are divided into two types:
1. DRIVER: equivalent to the main program of the tested module. It receives test data, transmits the data to the tested module, and then outputs the actual test results.
2. Pile module (stub): used to replace the sub-module called by the tested module. The pile module can perform a small amount of data operations without bringing all the functions of the sub-module, but it does not allow or do anything.
The measurement module and its related driver module and pile module constitute a "test environment", 2. Writing the driver module and the pile module brings additional overhead to the test. Because they are not delivered together as part of the product during software delivery, and their compilation requires a certain amount of work. In particular, the pile module cannot simply provide the information "once entered. In order to be able to correctly test the software, the pile module may need to simulate the functions of the actual sub-module, so that the establishment of the pile module is not very easy.

Figure 2 unit test environment
It is difficult and time-consuming to compile the pile module. In fact, you can avoid writing the pile module. You only need to compile the code of the actual pile module before the tested module in Project Progress Management. In this way, the test efficiency can be improved, and the testing frequency of the actual pile module can be improved to ensure the product quality more effectively. However, in order to ensure a stable and reliable practical pile module can be provided at the upper level and lay a good foundation for subsequent module tests, the driver module is still indispensable.
For each package or sub-system, we can compile a test module class based on the test cases to implement the driver module for all the modules to be tested in the test package. Instead of using a method to test the function in each class, we recommend that you test all methods in the class. The benefits include:
1. All methods or modules in the package can be tested at the same time, or the specified modules or methods can be easily tracked for testing.
2. All test cases can be used together to perform tests on the same piece of code to detect problems.
3. regression testing. After a module is modified, all modules or methods under test can be executed as long as the test class is executed. This not only makes it easy to check and track the modified Code, but also checks the impact of the modification on the related modules or methods in the package, so that the introduced modification errors can be detected in a timely manner.
4. Reuse the test method to ensure the durability of the test unit. You can use existing tests to compile related tests.
5. Separate the test code from the product code to make the code clearer and concise. This improves the maintainability of the test code and the tested code.
4.3 tracking and debugging
It is the best method to keep track of debugging, but not to thoroughly test the code. It is also a good tool for discovering the root cause of errors in program debugging.
After the test class is designed, it is best to use the code troubleshooting tool to track and debug the code segment to be tested to thoroughly check the logic errors of the Code. Existing Code development tools (such as JBuilder) are generally integrated with such troubleshooting tools. Troubleshooting tools are generally composed of execution control programs, execution status query programs, and tracing programs. The execution control program includes breakpoint definition, breakpoint revocation, one-step execution, breakpoint execution, and conditional execution. Execution status query programs include registers, stack status, variables, code, and other state information related to the program. A tracing program is used to track the sequence of events (for example, branches and subprograms) experienced during program execution ). Programmers can identify, locate, and correct program errors by identifying various States during program execution.
For module tracking and debugging, it is best to track and execute each test case for every modification to the tested module to eliminate all possible or introduced errors. In case of limited time, the driver module must also be called to execute all test cases once and trace and execute test cases with errors or exceptions once to find the root cause of the problem.
Troubleshooting is often a difficult process, especially for modules with complicated algorithms and many sub-modules. It is not easy to locate errors. Although troubleshooting is not a studious technique (sometimes people prefer to call it art), there are still some effective methods and strategies. The following describes the methods and strategies that should be used in troubleshooting.
1. breakpoint settings. Setting a breakpoint to track the source program can greatly improve the efficiency of troubleshooting. In general, in addition to settings based on experience and error information, you should also focus on the following types of statements.
1) function call statement. The Calling statement of a sub-function is the focus of the test. On the one hand, the interface reference error may occur when the sub-function is called, and on the other hand, the sub-function itself error may occur.
2) Determine transfer/loop statements. A judgment statement may often cause errors or failures due to boundary values and comparison priorities. Therefore, it is also an important test point for determining transfer/loop statements.
3) SQL statement. For database applications, SQL statements often occupy more important business logic in the module and are complex. Therefore, it is also a statement that is prone to errors.
4) complex algorithm segments. The error probability is often proportional to the complexity of the algorithm. Therefore, the more complex an algorithm, the more important it needs to be tracked, such as recursion and rollback.
2. View suspicious variables. When the program stops executing a statement, you can view the current value of the variable and the current attribute of the object. By comparing the current value and the expected value of these variables, you can easily locate the root cause of the program problem.
3. check SQL statement execution. Print the SQL statement that is suspected to be incorrect in the trace execution or running status, and re-query the analyzer (such as Oracle SQL plus) in the Database SQL query) SQL statement errors can be checked and corrected more efficiently.
4. Pay attention to the cluster phenomenon. Experience shows that the number of residual errors in the program after the test is proportional to the number of errors found in the program or the error detection rate. According to this rule, the program segments of the wrong cluster should be tested to improve the efficiency of the test investment. If you find that a code segment seems more prone to errors than other program modules, you should spend a lot of time and cost testing this program module.

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.