Software Testing MODULE2 NOTES
Software Testing MODULE2 NOTES
Functional Testing
Functional testing is a type of software testing that focuses on verifying
whether the software system functions according to the specified requirements.
It ensures that the application performs its intended functions correctly. During
functional testing, the tester evaluates the system's behavior against predefined
functional requirements or use cases, often without considering the internal
workings of the application. It helps ensure that the core features and functions
of the software deliver on the promise outlined in the requirements. It is
essential in ensuring that software behaves as expected in real-world scenarios,
meeting both user and business requirements. By performing tests like login
verification, form validation, and e-commerce functionality checks, you can
make sure that the software functions correctly, providing value to end users.
Key Points of Functional Testing:
1. Focus on Features and Functions: The primary focus is on validating
the functionality of the software. Test cases are designed to check if the
system behaves as expected for each function specified in the
requirements.
2. Test the User's Perspective: Functional testing is done from an end-user
perspective. It checks if the application meets the user's needs, inputs,
and outputs correctly.
3. No Concern for Code or Internal Logic: Functional testing doesn't
focus on the underlying code or internal workings of the application,
unlike structural or white-box testing.
4. Based on Functional Requirements: Functional testing uses
requirement documents, user stories, or functional specifications as a
reference point for creating test cases.
Types of Functional Testing:
1. Unit Testing: Testing individual components or modules of the software
in isolation to ensure that each part works as expected.
2. Integration Testing: Verifying the interaction between integrated
components or systems to ensure that they function correctly when
combined.
3. System Testing: Testing the complete integrated system to check if it
meets the specified functional requirements.
4. Sanity Testing: A quick round of testing to check if the basic
functionalities are working after a new build or code change.
5. Smoke Testing: A preliminary test to ensure that the most critical
functions of the software are working before proceeding with more
detailed testing.
6. Regression Testing: Ensuring that new code changes or fixes have not
adversely affected existing functionalities.
7. Acceptance Testing: Typically done by the end users or stakeholders to
determine whether the software meets their requirements and is ready for
production.
Examples of Functional Testing:
• Verifying if a login function accepts valid credentials and rejects invalid
ones.
• Checking if a user can correctly add items to a shopping cart in an e-
commerce website.
• Ensuring that data entered into a form is saved and retrieved correctly.
Key Aspects of Functional Testing:
• Objective: To verify that each function of the software application
operates according to the defined specifications.
• Scope: Focuses on user-facing functionality and system behavior.
• Test Basis: Functional requirements, user stories, and use cases.
• Non-Goal: Does not focus on internal code, performance, or system
design.
Example 1: Login Functionality in a Web Application
• Requirement: The system should allow users to log in using a valid
username and password.
• Test Case:
• Input: Correct username and password.
• Expected Outcome: The system logs the user in and redirects to the
homepage.
• Input: Incorrect username or password.
• Expected Outcome: The system displays an error message
indicating invalid credentials.
• Input: Empty fields for username or password.
• Expected Outcome: The system prompts the user to fill in the
required fields.
Example 2: E-Commerce Shopping Cart
• Requirement: Users should be able to add products to their shopping
cart and view the total amount.
• Test Case:
• Input: Select a product and click "Add to Cart."
• Expected Outcome: The product is added to the shopping cart, and
the cart count is updated.
• Input: View the cart after adding items.
• Expected Outcome: The cart displays the correct list of items and
the total price.
• Input: Remove a product from the cart.
• Expected Outcome: The item is removed, and the total price is
updated accordingly.
Example 3: Form Submission in a Web Application
• Requirement: A user should be able to submit a contact form with valid
information.
• Test Case:
• Input: Fill out the form with valid details (name, email, message)
and click "Submit."
• Expected Outcome: The system displays a confirmation message
saying "Thank you for contacting us."
• Input: Leave the email field empty.
• Expected Outcome: The system displays an error message
requesting a valid email.
• Input: Enter an invalid email format.
• Expected Outcome: The system displays an error message
indicating the email format is invalid.
Example 4: Search Functionality on a Website
• Requirement: The website should allow users to search for products by
entering keywords.
• Test Case:
• Input: Enter a valid search term (e.g., "laptop").
• Expected Outcome: The system returns a list of products related to
the term "laptop."
• Input: Enter a non-existent product name.
• Expected Outcome: The system displays a message like "No results
found."
• Input: Enter a blank search term.
• Expected Outcome: The system should show a message requesting
the user to enter a search term.
Example:
Scenario 1: Age Verification
• Requirement: A software system that checks the user's eligibility for a
particular service based on age, where the valid age range is between 18
and 60 (inclusive).
• Valid input range: 18 ≤ Age ≤ 60
• Test Cases:
• Minimum Boundary: Age = 18 (on the boundary)
• Just Inside Minimum: Age = 19 (just above the boundary)
• Just Outside Minimum: Age = 17 (just below the boundary,
invalid)
• Maximum Boundary: Age = 60 (on the boundary)
• Just Inside Maximum: Age = 59 (just below the boundary)
• Just Outside Maximum: Age = 61 (just above the boundary,
invalid)
These test cases ensure that the system correctly handles inputs at the
boundaries of the age range and rejects those outside the valid range.
Scenario 2: Input Validation for a Password Field
• Requirement: The system requires a password between 6 and 12
characters long.
• Valid input range: 6 ≤ Password Length ≤ 12
• Test Cases:
• Minimum Boundary: Password length = 6 characters
• Just Inside Minimum: Password length = 7 characters
• Just Outside Minimum: Password length = 5 characters (invalid)
• Maximum Boundary: Password length = 12 characters
• Just Inside Maximum: Password length = 11 characters
• Just Outside Maximum: Password length = 13 characters
(invalid)
Scenario 3: Discount Calculation Based on Purchase Amount
• Requirement: A discount is applied to customers whose purchase
amount is between $100 and $500.
• Valid input range: $100 ≤ Purchase Amount ≤ $500
• Test Cases:
• Minimum Boundary: Purchase amount = $100 (on the boundary)
• Just Inside Minimum: Purchase amount = $101 (just above the
boundary)
• Just Outside Minimum: Purchase amount = $99 (just below the
boundary, invalid)
• Maximum Boundary: Purchase amount = $500 (on the boundary)
• Just Inside Maximum: Purchase amount = $499 (just below the
boundary)
• Just Outside Maximum: Purchase amount = $501 (just above the
boundary, invalid)
Advantages of Boundary Value Analysis:
1. Effective Test Coverage: Since boundary values are often where defects
occur, BVA can uncover errors that may not be detected through regular
testing.
2. Simplicity: BVA is a simple and effective technique that helps identify
edge cases with minimal effort.
3. Reduces the Number of Test Cases: By focusing on boundary values,
it reduces the number of test cases compared to testing every possible
input value.
2. Branch Coverage:
• Also known as Decision Coverage, this technique ensures that
every decision (i.e., every branch of conditional statements
like if, switch, for, while, etc.) is tested.
• Goal: Achieve 100% branch coverage by ensuring that every
possible outcome of each condition is tested.
Example: For an if-else statement, both the "if" branch and the "else" branch
should be tested.
3. Path Coverage:
• Path coverage ensures that all possible paths through a given
program are tested. A path represents a unique sequence of events
or conditions in the program.
• Goal: Test all possible execution paths within the code.
Example: If a program has multiple if conditions, path coverage tests all
possible combinations of conditions, ensuring that every possible route through
the code is executed.
4. Condition Coverage:
• This technique involves testing each boolean condition within a
decision to ensure that each condition has been evaluated to both
true and false at least once.
• Goal: Achieve 100% condition coverage by testing each
condition's possible outcomes.
Example: For a condition if (a > 0 && b < 5), both a > 0 and b < 5 should be
tested to evaluate both their true and false states.
5. Multiple Condition Coverage:
• This technique ensures that all possible combinations of conditions
within a decision are tested. This is more thorough than simple
condition or branch coverage.
• Goal: Test all combinations of individual conditions within a
compound statement.
Example: For the condition if (a > 0 && b < 5 && c == 10), multiple condition
coverage tests all combinations of a > 0, b < 5, and c == 10 to evaluate the true
and false results.
6. Loop Coverage:
• This testing technique ensures that loops are tested for different
scenarios, including zero iterations, one iteration, and multiple
iterations.
• Goal: Ensure that loop-related logic is thoroughly tested.
Example: If a loop is written as for (int i = 0; i < n; i++), test cases should
ensure that n = 0, n = 1, and other values for n are covered to test the loop's
behavior.
Advantages of Structural Testing:
1. Thoroughness: Structural testing provides a detailed and thorough
evaluation of the internal workings of the application. It helps to identify
issues that might not be visible through black-box testing.
2. Code Quality: By ensuring that all paths, conditions, and statements are
tested, it helps improve code quality and maintainability.
3. Early Detection of Errors: Structural testing helps detect errors early in
the development process, especially in areas related to logic, algorithm,
and performance.
4. Comprehensive Coverage: When performed properly, structural testing
ensures that the entire codebase is covered and tested.
Disadvantages of Structural Testing:
1. Requires Code Knowledge: Unlike black-box testing, structural testing
requires testers to have a deep understanding of the code, which may not
always be possible, especially for external testers.
2. High Complexity: For large and complex systems, achieving complete
coverage (100%) can be difficult due to the sheer number of paths,
conditions, and loops in the code.
3. Time-Consuming: Testing all the paths and conditions in large
applications can be time-consuming and resource-intensive.
4. Not Always Applicable: In some cases, structural testing may be
difficult to apply, particularly in systems where the source code is
unavailable or when the internal logic is too complex to test exhaustively.
1. Statement Coverage
Statement coverage ensures that every statement in the code is executed at least
once during testing. The goal is to ensure that all lines of code are tested,
minimizing untested parts of the code.
Example:
python
Copy
def check number(x): if x > 10: print("x is greater than 10") else: print("x is
less than or equal to 10")
• Statement Coverage requires that both print() statements are executed
during testing.
• Test Cases:
• Test Case 1: x = 15 → The condition x > 10 is true, so "x is greater
than 10" is printed.
• Test Case 2: x = 5 → The condition x > 10 is false, so "x is less
than or equal to 10" is printed.
Here, both branches are tested, so Statement Coverage is satisfied.
3. Path Coverage
Path coverage ensures that all possible execution paths in the code are tested.
This is a more comprehensive technique compared to branch coverage because
it considers all possible combinations of branches.
Example:
python
Copy
def evaluate_numbers(a, b): if a > 10: if b < 5: print("Path 1") else: print("Path
2") else: print("Path 3")
• Path Coverage requires testing all possible paths through the code:
• Path 1: a > 10 and b < 5
• Path 2: a > 10 and b >= 5
• Path 3: a <= 10
• Test Cases:
• Test Case 1: a = 15, b = 3 → Path 1 is executed, printing "Path 1".
• Test Case 2: a = 15, b = 6 → Path 2 is executed, printing "Path 2".
• Test Case 3: a = 5, b = 3 → Path 3 is executed, printing "Path 3".
By testing these cases, Path Coverage ensures that every path is executed.
4. Condition Coverage
Condition coverage ensures that each individual condition in a decision (like
in if statements) is tested for both true and false outcomes. It's more granular
than branch coverage because it tests each condition independently.
Example:
python
Copy
def check_conditions(a, b): if a > 0 and b < 10: print("Condition met") else:
print("Condition not met")
• Condition Coverage requires testing the individual conditions (a >
0 and b < 10) both as true and false.
• Test Cases:
• Test Case 1: a = 5, b = 3 → a > 0 is true, b < 10 is true (both
conditions are true).
• Test Case 2: a = -5, b = 3 → a > 0 is false, b < 10 is true (first
condition is false).
• Test Case 3: a = 5, b = 15 → a > 0 is true, b < 10 is false (second
condition is false).
• Test Case 4: a = -5, b = 15 → a > 0 is false, b < 10 is false (both
conditions are false).
This ensures that both conditions are tested for both outcomes, so Condition
Coverage is satisfied.
6. Loop Coverage
Loop coverage ensures that loops are tested in various scenarios, including
cases where the loop runs zero times, once, and multiple times.
Example:
python
Copy
def check_numbers(n): for i in range(n): print(i)
• Loop Coverage ensures the loop is tested for different values of n:
• Test Case 1: n = 0 → The loop runs zero times.
• Test Case 2: n = 1 → The loop runs once.
• Test Case 3: n = 5 → The loop runs five times.
Path Testing is a structural testing technique that focuses on ensuring that all
possible paths through a program's code are tested. It is a form of Whitebox
Testing where the goal is to verify the behavior of the software by exercising
different execution paths of the program. It ensures all logical paths in a
program are tested. While it provides thorough code coverage and is
particularly useful for detecting logic errors and edge cases, it can be complex
and resource-intensive, especially for large programs with many conditions
and loops. Path testing works best in combination with other testing techniques
like statement coverage, branch coverage, and condition coverage to ensure
comprehensive testing of both the internal logic and functionality of the
software.
3. Path Coverage
Path coverage measures the percentage of all possible paths through the
program that have been tested. Path coverage ensures that all potential
execution sequences are tested.
Formula:
Path Coverage (%)=Number of paths testedTotal number of paths×100Path C
overage (%)=Total number of pathsNumber of paths tested×100
Example:
Consider a simple function with an if-else condition:
python
Copy
def check_number(a, b): if a > 0: if b > 0: print("Both positive") else: print("a
positive, b non-positive") else: print("a non-positive")
There are four possible paths to consider:
1. a > 0 and b > 0
2. a > 0 and b <= 0
3. a <= 0 and b > 0
4. a <= 0 and b <= 0
To achieve 100% path coverage, all four test cases must be executed.
4. Condition Coverage
Condition coverage measures whether each individual condition in a decision
(like if, else, or while) has been evaluated to both true and false at least once.
Formula:
Condition Coverage (%)=Number of conditions evaluatedTotal number of co
nditions×100Condition Coverage (%)=Total number of conditionsNumber of
conditions evaluated×100
Example:
Consider the following code:
python
Copy
def check_number(a, b): if a > 0 and b < 10: print("Valid") else:
print("Invalid")
There are two conditions: a > 0 and b < 10. To achieve 100% condition
coverage, both conditions must be tested for both true and false:
• Test Case 1: a = 5, b = 3 (both conditions true)
• Test Case 2: a = -5, b = 3 (first condition false)
• Test Case 3: a = 5, b = 20 (second condition false)
By running these tests, you ensure that both conditions have been evaluated for
both true and false, achieving 100% Condition Coverage.
5. Function Coverage
Function coverage measures whether each function in the program has been
called during the test. It ensures that all functions in the code are tested at least
once.
Formula:
Function Coverage (%)=Number of functions calledTotal number of function
s×100Function Coverage (%)=Total number of functionsNumber of functions
called×100
Example:
For a program with the following functions:
python
Copy
def add(a, b): return a + b def subtract(a, b): return a - b
If the test suite contains a test that calls both add() and subtract(), the Function
Coverage will be 100%.
6. Loop Coverage
Loop coverage ensures that every loop in the program is tested for multiple
conditions:
• When the loop runs 0 times (e.g., the loop condition is initially false).
• When the loop runs 1 time.
• When the loop runs more than once.
Formula:
Loop Coverage (%)=Number of loop conditions testedTotal number of loop c
onditions×100Loop Coverage (%)=Total number of loop conditionsNumber
of loop conditions tested×100
Example:
For a loop like:
python
Copy
for i in range(5): print(i)
• Test Case 1: range(0) → Loop does not execute (0 times).
• Test Case 2: range(5) → Loop executes 5 times.
For full loop coverage, you must test both the case where the loop executes 0
times and where it executes multiple times.
7. Requirements Coverage
Requirements coverage measures whether all specified requirements of the
software have been covered by test cases. This is a form of black-box
testing where the focus is on ensuring that the system meets its requirements
as specified in the documentation.
Formula:
Requirements Coverage (%)=Number of requirements testedTotal number of
requirements×100Requirements Coverage (%)=Total number of requirements
Number of requirements tested×100
Example:
If a system has 10 requirements and 8 of those are tested by the current test
suite, the Requirements Coverage would be 810×100=80%108×100=80%.
8. Mutation Coverage
Mutation coverage is a more advanced metric that involves introducing small
changes (mutations) to the code and ensuring that the test suite detects these
changes. The goal is to check whether the tests are effective in detecting subtle
changes or errors.
Formula:
Mutation Coverage (%)=Number of mutations killedTotal number of mutatio
ns×100Mutation Coverage (%)=Total number of mutationsNumber of mutati
ons killed×100
Example:
If you introduce 10 mutations into the code and the test suite detects 8 of them,
the Mutation Coverage would be 810×100=80%108×100=80%.
Basis Path Testing is a white-box testing technique that focuses on ensuring
that all possible paths in a program are covered through a minimal set of test
cases. It is based on Control Flow Graphs (CFG) and involves identifying
independent paths that cover all possible decision points, ensuring the entire
codebase has been tested for potential execution paths.
The goal of basis path testing is to provide maximum test coverage with the
least number of test cases, by selecting paths that independently cover all
unique paths through the program's flow.
Key Concepts in Basis Path Testing
1. Control Flow Graph (CFG):
A CFG is a graphical representation of a program’s control structure,
where:
• Nodes represent program statements or blocks of code.
• Edges represent possible control flow between those statements.
The basis path testing technique relies on building a CFG to analyze all paths
through the program.
2. Independent Paths:
Independent paths are paths that introduce at least one new decision
point or edge. These paths are crucial for ensuring complete coverage,
as they represent different execution scenarios that cannot be replicated
by any other path in the program.
3. Cyclomatic Complexity:
Cyclomatic complexity is a metric used in basis path testing to measure
the number of linearly independent paths through a program. It helps
determine the minimum number of test cases needed for complete path
coverage.
Cyclomatic Complexity (V) can be calculated using the formula:
𝑉(𝐺)=𝐸−𝑁+2𝑃V(G)=E−N+2P
where:
• 𝑉(𝐺)V(G) = Cyclomatic Complexity
• 𝐸E = Number of edges in the control flow graph
• 𝑁N = Number of nodes in the control flow graph
• 𝑃P = Number of connected components (usually 1 for a single
program)
Steps in Basis Path Testing
1. Create a Control Flow Graph (CFG):
• Convert the program into a control flow graph by identifying nodes
(statements or blocks of code) and edges (possible control flows
between those statements).
2. Calculate Cyclomatic Complexity:
• Use the formula to calculate the cyclomatic complexity. This will
tell you the number of independent paths that need to be tested.
3. Identify Independent Paths:
• Identify the set of independent paths through the CFG. These are
the paths that need to be tested to ensure maximum coverage.
Independent paths can be selected based on decision points (such
as if statements, loops, and switches).
4. Design Test Cases:
• For each independent path, create a corresponding test case that
exercises that specific path. These test cases will ensure all paths in
the program are covered.
5. Execute the Test Cases:
• Run the designed test cases and observe whether each path behaves
as expected. This helps to ensure the program works under all
possible execution scenarios.
Example of Basis Path Testing
Let's consider a simple function in Python:
python
Copy
def check_number(a, b): if a > 0: if b > 0: return "Both positive" else: return "a
positive, b non-positive" else: return "a non-positive"
Step 1: Create the Control Flow Graph (CFG)
• Nodes:
• Node 1: a > 0
• Node 2: b > 0
• Node 3: return "Both positive"
• Node 4: return "a positive, b non-positive"
• Node 5: return "a non-positive"
• Edges:
• Edge 1: From Node 1 to Node 2 (if a > 0)
• Edge 2: From Node 2 to Node 3 (if b > 0)
• Edge 3: From Node 2 to Node 4 (if b <= 0)
• Edge 4: From Node 1 to Node 5 (if a <= 0)
Step 2: Calculate Cyclomatic Complexity
Using the formula 𝑉(𝐺)=𝐸−𝑁+2𝑃V(G)=E−N+2P, where:
• 𝐸E = 4 (edges),
• 𝑁N = 5 (nodes),
• 𝑃P = 1 (since it's a single program).
𝑉(𝐺)=4−5+2(1)=1V(G)=4−5+2(1)=1
This means there is 1 independent path in the program, indicating a minimal
set of paths needed for complete coverage.
Step 3: Identify Independent Paths
The independent paths in this case would be:
• Path 1: a <= 0 (goes to Node 5)
• Path 2: a > 0 and b > 0 (goes to Node 3)
• Path 3: a > 0 and b <= 0 (goes to Node 4)
These three paths cover all decision points and unique execution flows in the
program.
Step 4: Design Test Cases
For each independent path:
• Test Case 1: check_number(-5, 3) → Path 1 (a <= 0)
• Test Case 2: check_number(5, 3) → Path 2 (a > 0 and b > 0)
• Test Case 3: check_number(5, -3) → Path 3 (a > 0 and b <= 0)
Step 5: Execute the Test Cases
• Test Case 1: check_number(-5, 3) → Expected output: "a non-positive"
• Test Case 2: check_number(5, 3) → Expected output: "Both positive"
• Test Case 3: check_number(5, -3) → Expected output: "a positive, b
non-positive"
Dataflow Testing is a white-box testing technique used to identify and test the
flow of data within a program. It focuses on the points at which variables
receive values (definitions) and where those values are used (uses). The
primary aim of dataflow testing is to ensure that the program correctly handles
the flow of data between variables and functions, with particular attention
given to variables' definitions and their uses.
Dataflow testing involves:
1. Definition of a variable: When a variable is assigned a value.
2. Use of a variable: When the value of a variable is read or used.
The technique examines the paths of data through the program, helping to
identify potential problems like undefined variables, incorrect variable use,
or data corruption. It uses the concept of Control Flow Graphs (CFG) to
track data flow between variable definitions and uses.