Unit 2
Unit 2
Structural Testing is a type of software testing. This testing is used to test the internal design
of the software or the structure of the coding for the particular software. Structural testing
uses white box testing techniques. The structural testing is concentrated on how the system is
doing rather than the functionality of the system. Most of the time structural testing is also
referred to as 'White Box Testing' and also as open, transparent, or glass testing based on the
code.
Types of Structural Testing
1. Mutation Testing
Mutation testing is structural testing that is performed to design new software tests
and also evaluate the quality of tests. It is related to the modification of a program in
small ways.
It is a structural testing technique, which uses the structure of the code to guide the
testing process. Mutation testing has the following three types:
• Value Mutation
• Decision Mutation
• Statement Mutation
Let us understand this using examples.
Value Mutation: It is mutation testing that changes the values of constants to detect
errors. Let us see a simple example to understand it. The following is the initial code
snippet:
int a=10;
int b=20;
int c= a*b;
int a=5;
int b=20;
int c=a*b;
Value of integer 'a' has been changed to 5 and the output is directed to observe if
there exist any errors in the code.
int a=10;
int b=2;
if(a%2==0)
printf("hello")
int a=10;
int b=2;
if(a/b==0)
printf("hello")
}
Statement Mutation: A statement mutation either deletes a statement or replaces
the statement to check for errors.
int a=10;
int b=5;
int c= a*b;
Now the statement(s) of the code is changed to see if it arises any errors.
int a=10;
int b=5;
float x=a/b;
Data Flow testing is structural testing it is used to find the test paths of a program
according to the values. It is used to analyze the flow of data in the program. These
are mainly concerned with
1. read a,b
2. if a>b
3. c=a-b
4. else
5. c=b-a
6. print(c)
a 1 2,3,5
b 1 2,3,5
c 3,5 6
Basis path testing is a type of white-box testing that tests all possible independent paths in the
control flow graph of a program.
Note:
• A path is the route of nodes in the control flow graph that a program takes from one
point to another.
• An independent path is a path that adds at least one node in the already defined
independent paths. In other words, the independent paths of a program are all unique.
Test coverage
Test coverage is defined as a metric in Software Testing that measures the amount of testing
performed by a set of test. It will include gathering information about which parts of a program
are executed when running the test suite to determine which branches of conditional statements
have been taken.
In simple terms, it is a technique to ensure that your tests are testing your code or how much
of your code you exercised by running the test.
There are several types of test coverage metrics, each focusing on different aspects of the code:
Test coverage metrics provide valuable insights into the quality and reliability of the software
under test. However, achieving 100% test coverage does not guarantee the absence of defects
or errors in the code. It is essential to prioritize test coverage based on criticality, complexity,
and risk factors associated with different code segments. Additionally, test coverage should be
complemented with other testing techniques such as boundary testing, equivalence partitioning,
and error guessing to ensure comprehensive validation of the software.
Advantages:
1. Limited Scope: Test coverage metrics provide insights into the extent of code
execution but do not guarantee the absence of defects or errors. Achieving 100% test
coverage does not guarantee the correctness or robustness of the software as it may still
contain logic errors or integration issues.
2. Focus on Quantity over Quality: Focusing solely on achieving high test coverage may
lead to a false sense of security, where the emphasis is placed on the quantity of tests
rather than their quality. It is essential to complement test coverage metrics with other
testing techniques to ensure thorough validation of the software.
3. Complexity: Achieving 100% test coverage, especially for large and complex systems,
can be challenging and impractical. Path coverage, in particular, is often difficult to
achieve due to the exponential number of possible execution paths through the code.
4. Maintenance Overhead: Test coverage metrics require ongoing maintenance and
monitoring to ensure that they remain relevant and effective. As the codebase evolves
over time, test cases may need to be updated or modified to reflect changes in the
software.
5. False Sense of Completion: Relying solely on test coverage metrics may lead to a false
sense of completion, where teams believe that achieving high test coverage is sufficient
to ensure software quality. It is essential to supplement test coverage metrics with other
quality assurance practices such as code reviews, static analysis, and user acceptance
testing.
Slice-Based Testing
Slice-Based Testing is a structural testing technique used to identify and test subsets or "slices"
of a software program's functionality. It focuses on selecting and testing portions of the code
that are relevant to specific requirements or features, rather than testing the entire program as
a whole. This approach allows testers to achieve better test coverage and efficiency by targeting
critical areas of the codebase.
1. Identifying Slices: The first step in slice-based testing is to identify slices of the code
that correspond to specific features, functions, or requirements of the software. Slices
are subsets of the codebase that encapsulate the relevant statements, branches, and
variables related to a particular functionality.
2. Creating Test Cases: Once slices are identified, test cases are designed to exercise the
functionality represented by each slice. Test cases should cover various scenarios, input
combinations, and boundary conditions to ensure comprehensive testing coverage
within each slice.
3. Executing Test Cases: Test cases are executed against the corresponding slices of the
code to verify the correctness and robustness of the implemented functionality. Test
results are recorded, and any discrepancies or failures are analyzed and addressed by
developers.
4. Iterative Process: Slice-based testing is an iterative process that involves refining and
expanding the set of slices and test cases as the software evolves. New slices may be
identified, and existing test cases may be updated or augmented to accommodate
changes in the codebase or requirements.
Advantages of Slice-Based Testing:
1. Focused Testing: Slice-based testing allows testers to focus their efforts on specific
areas of the code that are relevant to the software's requirements or features. This
targeted approach enhances test coverage and effectiveness by prioritizing critical
functionalities.
2. Efficiency: By testing smaller subsets of the code, slice-based testing can be more
efficient compared to testing the entire program. Testers can achieve thorough coverage
of critical functionalities while minimizing the time and resources required for testing.
3. Early Detection of Defects: Slice-based testing facilitates early detection of defects or
errors in the code by enabling testers to focus on individual slices and functionalities.
This allows for prompt resolution of issues before they escalate and impact the overall
quality of the software.
4. Improved Maintainability: By breaking down the codebase into smaller, manageable
slices, slice-based testing enhances the maintainability and scalability of the testing
process. Test cases can be easily maintained, updated, and reused as the software
evolves over time.
5. Enhanced Debugging: Testing individual slices of the code makes it easier to isolate
and debug issues, as the scope of analysis is limited to specific functionalities. This
accelerates the troubleshooting process and improves the overall efficiency of defect
resolution.
In summary, slice-based testing is a valuable technique for achieving focused and efficient
testing of software functionalities. By breaking down the codebase into smaller, manageable
slices, testers can achieve thorough coverage and early detection of defects, leading to
improved software quality and reliability. However, it is essential to address challenges related
to dependency management, integration testing, and complexity to maximize the effectiveness
of slice-based testing in real-world scenarios.
A retrospective on structural testing
A retrospective on structural testing with a focus on identifying gaps and redundancies involves
a thorough review of the testing process to uncover areas where testing may have been
insufficient, incomplete, or inefficient. Let's discuss this in detail:
Metrics for method evaluation in structural testing focus on assessing the effectiveness,
coverage, and quality of the testing process with respect to the internal structure of the software
code. These metrics help evaluate how thoroughly the code has been tested, identify areas of
improvement, and ensure that the testing process meets its objectives. Here's a detailed
discussion on metrics commonly used for evaluating structural testing:
1. Statement Coverage:
• Definition: Statement coverage measures the percentage of executable
statements in the code that have been executed by the test cases.
• Purpose: It indicates the extent to which the code has been exercised during
testing and helps identify untested or unreachable code.
• Example: If a function contains 20 executable statements, and the test cases
cover 16 of them, the statement coverage would be 80%.
2. Branch Coverage:
• Definition: Branch coverage measures the percentage of decision points
(branches) in the code that have been executed by the test cases.
• Purpose: It ensures that all possible outcomes of conditional statements and
loops are tested, helping identify potential logic errors and corner cases.
• Example: If a decision point has two possible outcomes (branches), and the test
cases cover both branches, the branch coverage would be 100%.
3. Path Coverage:
• Definition: Path coverage measures the percentage of all possible execution
paths through the code that have been exercised by the test cases.
• Purpose: It ensures that all possible combinations of conditions and loops are
tested, providing more thorough coverage of the code.
•Example: If a function has multiple conditional statements and loops, each
unique combination of paths through the code represents a separate execution
path.
4. Cyclomatic Complexity:
• Definition: Cyclomatic complexity is a quantitative measure of the complexity
of a program, calculated based on the number of linearly independent paths
through the code.
• Purpose: It helps identify complex areas of the code that may require additional
testing and validation, as higher complexity correlates with increased risk of
defects.
• Example: A function with a cyclomatic complexity of 10 indicates that there
are 10 linearly independent paths through the code.
5. Mutation Score:
• Definition: Mutation testing involves introducing small changes (mutations) to
the code and then running the test suite to see if any of the mutations are
detected.
• Purpose: Mutation score represents the percentage of mutations detected by the
test cases, indicating the effectiveness of the test suite in detecting code changes.
• Example: If 80% of introduced mutations are detected by the test cases, the
mutation score would be 80%.
6. Function and Method Coverage:
• Definition: Function and method coverage measure the percentage of functions
or methods in the codebase that have been executed by the test cases.
• Purpose: It ensures that all functions and methods are tested, helping identify
potential defects and ensuring comprehensive code coverage.
• Example: If the test cases cover 15 out of 20 functions in the codebase, the
function coverage would be 75%.
These metrics provide quantitative measures of the thoroughness and effectiveness of structural
testing methods. By analyzing these metrics, software development teams can identify areas
for improvement, optimize testing strategies, and ensure the reliability and quality of their
software products.