Unit-3 Unit Testing
Unit-3 Unit Testing
3. Manual Testing:
Manual testing is one of the most important ways to test software because it can
find both obvious and hidden bugs.
Types of Manual Testing
Manual testing can be done in many ways.
White Box Testing
Black Box Testing
Gray Box Testing
Cont..
White Box Testing is also known as clear box testing, open box
testing or glass box testing.
The tester needs to have knowledge of the code, architecture, and logic
behind the application.
Techniques used in White Box Testing:
Unit Testing:
Testing individual units or components of the software.
Integration Testing
Testing the interaction between integrated units or components.
Code Coverage Analysis
Ensuring that all code paths are tested.
a technique used to measure how much of your code is executed when your tests
run.
Statement Coverage: Ensures that each statement in the code is executed at
least once
Branch Coverage: Ensures that each branch (true/false) in control structures (like
if-else) is executed at least once.
Function Coverage: Ensures that each function is called at least once.
Condition Coverage: Ensures that each Boolean sub-expression in the code is
evaluated to be both true and false.
Name Stmts Miss Cover Missing
---------------------------------------------
factorial.py 12 0 100%
test_factorial.py 10 0 100%
---------------------------------------------
TOTAL 22 0 100%
Cont..
Advantages:
Identifies hidden errors and vulnerabilities in the code.
Optimizes code by discovering unnecessary code paths.
Enhances code quality and security.
Disadvantages:
• Requires knowledge of programming and code structure.
• Can be time-consuming and complex.
Black Box Testing
Testers only know what the software is supposed to do, not how it does
it.
Techniques Used in Black Box Testing:
Functional Testing:
Verifying that the software functions as expected.
Non-Functional Testing
Testing performance, usability, reliability, etc.
Regression Testing
Ensuring that new code changes do not adversely affect existing functionality.
Boundary Value Testing
Testing the boundaries between partitions.
It involves testing at the edges of input ranges to uncover errors at the
boundaries of input space.
Example
If a given age qualifies for a senior citizen discount, where the qualifying range is
between 60 to 100 inclusive.
The boundaries for age input are:
Lower Boundary – 60
Upper Boundary - 100
Cont..
Equivalence Partitioning
Dividing input data into valid and invalid partitions and testing each partition.
A set of valid or invalid input values that are treated similarly by the system.
Example
consider a function that validates the age of a user for an online service, where the
valid age range is between 18 and 65 inclusive.
Valid age range: 18 to 65
Invalid age ranges:
Below 18
Above 65
Cont..
•Actions:
•Apply 20% discount
•Apply 15% discount
•Apply 10% discount
•Apply No Discount
Transitions:
• From Logged Out to Logged In on valid login
• From Logged Out to Locked on three consecutive invalid login attempts
• From Locked to Logged Out on reset
• From Logged In to Logged Out on logout
Cont..
Advantages:
• Tests are done from the user’s perspective.
• No need for programming knowledge.
• Effective for large-scale software systems.
Disadvantages:
• Limited coverage of the software’s internal structure.
• May miss certain types of errors that white box testing would catch.
Gray Box Testing
Gray box testing is a combination of both white box and black box
testing.
Testers have partial knowledge of the internal workings of the
application, which allows them to design better test cases.
Techniques used in Gray Box Testing:
Matrix Testing
Using matrices to determine the impact of different input combinations on the
system.
It is particularly useful for identifying dependencies and interactions among
different parts of the system.
Example: Testing a Login System
Input Variables:
1. Username (valid, invalid, empty)
2. Password (valid, invalid, empty)
Matrix
Regression Testing
Ensuring that changes do not affect existing functionality.
Scenario: E-commerce Website
Initial Features:
1. User Registration
2. User Login
3. Product Search
4. Add to Cart
5. Checkout
Cont..
Recent Changes:
1. Added a new payment gateway
2. Updated the user profile section
User Login:
1. Login with valid credentials.
2. Login with invalid credentials.
3. Login with an unregistered email.
4. Login with empty field
Product Search:
5. Search for an existing product.
6. Search for a non-existing product.
7. Search with an empty query.
Cont..
Add to Cart:
1. Add an available product to the cart.
2. Add an out-of-stock product to the cart.
3. Update the quantity of a product in the cart.
4. Remove a product from the cart
Checkout:
5. Checkout with all mandatory fields filled.
6. Checkout with missing shipping information.
7. Checkout using different payment methods.
Cont..
@Test
public void testValidLogin() {
WebElement emailField = driver.findElement(By.id("email"));
WebElement passwordField = driver.findElement(By.id("password"));
WebElement loginButton = driver.findElement(By.id("loginButton"));
emailField.sendKeys("[email protected]");
passwordField.sendKeys("validPassword");
loginButton.click();
WebElement homepage = driver.findElement(By.id("homepage"));
Assert.assertTrue(homepage.isDisplayed(), "Login failed with valid credentials");
}
Cont..
@Test
public void testInvalidLogin() {
WebElement emailField = driver.findElement(By.id("email"));
WebElement passwordField = driver.findElement(By.id("password"));
WebElement loginButton = driver.findElement(By.id("loginButton"));
emailField.sendKeys("[email protected]");
passwordField.sendKeys("invalidPassword");
loginButton.click();
WebElement errorMessage = driver.findElement(By.id("errorMessage"));
Assert.assertTrue(errorMessage.isDisplayed(), "Error message not displayed
for invalid login");
}
Cont..
Pattern Testing
Using patterns to test common faults.
This approach helps identify issues related to common design patterns, data
structures, or functional requirements.
Scenario: Input Validation for User Registration Form
Fields to Test:
1. Username
2. Password
3. Email
4. Phone Number
Cont..
Patterns to Test:
1. Username: Alphanumeric, 3-20 characters
2. Password: At least 8 characters, includes a mix of uppercase, lowercase,
digits, and special characters
3. Email: Standard email format
4. Phone Number: 10 digits
Cont..
Advantages:
• Balances the benefits of both white box and black box testing.
• Provides a more comprehensive testing approach.
• More effective in finding defects that are related to system behavior and code
structure.
Disadvantages:
• Requires knowledge of both the internal structure and external behavior.
• Can be complex and time-consuming.
2. Automation Testing:
Automated unit testing is another approach to software testing, and it involves
using specialized tools to test scripts automatically.
Methodologies for Automated Testing
The following are three strategies and approaches within automation testing that
will aid the test engineer in improving the quality of the software product being
tested.
1. Code-Driven
2. GUI Testing
3. Test Automation Framework
Code-Driven Testing
Key Aspects:
Unit Testing: Automated tests are written to test the smallest parts of
an application, typically functions or methods.
Automated Test Scripts: Scripts are created to run the tests, compare
actual results with expected results, and report discrepancies.
Advantages:
• Ensures that individual components work as expected.
• Helps in identifying bugs early in the development process.
• Can be run frequently without manual intervention.
Disadvantages:
• Requires knowledge of programming and test scripting.
• Maintenance can be challenging if the codebase changes frequently.
GUI Testing
This can include verifying the visual elements, user interactions, and
overall user experience.
Cont..
Key Aspects:
Automated GUI Test Tools: Tools like Selenium, QTP, or TestComplete can
be used to automate GUI tests.
User Interaction Simulation: The tests simulate user interactions with the
application, such as clicking buttons, entering text, and navigating through
menus.
Advantages:
• Validates the user interface and user experience.
• Can catch visual bugs and issues with user interactions.
• Useful for regression testing to ensure new changes don’t break existing
functionality.
Disadvantages:
• Can be brittle; minor changes in the UI may require test script updates.
• Typically slower than other forms of automated testing.
• Requires tools and frameworks specific to GUI testing.
Test Automation Framework
Advantages:
• Provides a structured approach, reducing maintenance effort.
• Enhances reusability of test scripts and components.
• Improves test coverage and efficiency.
Disadvantages:
• Initial setup can be complex and time-consuming.
• Requires knowledge of both the application under test and the framework
being used.
• May require ongoing maintenance as the application and framework evolve.
Coverage Analysis
This technique is very popular due to its simplicity and effectiveness. We identify
paths of the program and write test cases to execute those paths.
Each path covers a portion of the program.
We define ‘coverage’ as a ‘percentage of source code that has been tested with
respect to the total source code available for testing’.
We may like to achieve a reasonable level of coverage using control flow testing.
Following testing techniques are used to analyse the coverage:
1) Statement Coverage
2) Branch Coverage
3) Condition Coverage
4) Path Coverage
1) Statement Coverage:
In a programming language, a statement is nothing but the line of code or instruction
for the computer to understand and act accordingly.
It is the method of validating whether each and every line of the code is executed
at least once.
It is used to calculate the total number of executed statements in the source code
out of total statements present in the source code.
The goal of statement coverage technique is to cover all the possible executing
statements and path lines in the code.
Statement coverage= * 100
Cont..
#include<stdio.h>
#include<conio.h>
void main()
{
int a,b,c,x=0,y=0;
clrscr();
printf("Enter three numbers:");
scanf("%d %d %d",&a,&b,&c);
if((a>b)&&(a>c)){
x=a*a+b*b;
}
if(b>c){
y=a*a-b*b;
}
printf("x= %d y= %d",x,y);
getch();
}
2) Branch Coverage:
Branch coverage or Decision coverage technique is used to cover all branches of
the control flow graph.
It covers all the possible outcomes (true and false) of each condition of decision
point at least once.
branch coverage follows decision point and branch coverage edges.
Many different metrics can be used to find branch coverage and decision
coverage, but some of the most basic metrics are:
finding the percentage of program
paths of execution during the execution of the program.
V(G)= E-N+2P
A+B>50
= 8-7+2
Large
Number
V(G) = 3
End if
A+B<50
Small
Number
End if
Mutation Testing
Mutation testing helps assess the effectiveness and quality of a test suit
and enhances the test suite, if it is not adequate for a program.
Mutation and Mutants
The mutants generated by making only one change are known as first
order mutants.
We may obtain second order mutants by making two simple changes in
the program and third order mutants by making three simple changes,
and so on.
The second order mutants and above are called higher order
mutants.
Generally, in practice, we prefer to use only first order mutants in order
to simplify the process of mutation.
Cont..
Mutation Operators
When we execute a mutant using a test suite, we may have any of the
following outcomes:
The results of the program are affected by the change and any test case of
the test suite detects it. If this happens, then the mutant is called a killed
mutant (the test fails).
The results of the program are not affected by the change and any test case
of the test suite does not detect the mutation. The mutant is called a live
mutant (the test passes despite the change).
The mutation score associated with a test suite and its mutants is
calculated as:
Cont..
The total number of mutants is equal to the number of killed mutants plus
the number of live mutants.
The mutation score measures how sensitive the program is to the changes
and how accurate the test suite is.
A mutation score is always between 0 and 1.
A higher value of mutation score indicates the effectiveness of the test suite
although effectiveness also depends on the types of faults that the mutation
operators are designed to represent.
The test cases that identify the changed behaviour should be preserved and
transferred to the original test suite in order to enhance the capability of the
test suite.
Hence, the purpose of mutation testing is not only to assess the capability of
a test suite but also to enhance the test suite.
Mutation testing tools are also available in the market like Insure++, Jester
for Java (open source) and Nester for C++ (open source).
Example - Consider the program to find the largest of three numbers
A B C Expected
Outcome
6 10 2 10
10 6 2 10
6 2 10 10
6 10 20 20
Generate five mutants (M1 to M5) and calculate the mutation score of this test suite
Solution
Muted Statement
Mutant No. Line No Original Line Modified Line
M1 11 If (A > B) If (A < B)
M2 11 If (A > B) If (A > (B + C))
M3 12 If (A > C) If ( A < C)
M4 20 If ( C > B) If ( C = B)
M5 16 Printf(“The Printf(“The
Largest Number Largest Number
is :%f\n”,C) is :%f\n”,B)
The actual output obtained by
executing the mutants M1-M5
Actual Output of Mutant M1
Mutant M1:
• Test Case 1: Expected 10, Actual 6 (Killed)
• Test Case 2: Expected 10, Actual 6 (Killed)
Mutant M1 is killed.
Mutant M2:
• All test cases produce the expected output.
Mutant M2 is not killed.
Summary
Mutant M3:
• Test Case 2: Expected 10, Actual 2 (Killed)
• Test Case 3: Expected 10, Actual 6 (Killed)
Mutant M3 is killed.
Mutant M4:
• Test Case 4: Expected 20, Actual 10 (Killed)
Mutant M4 is killed.
Summary
Mutant M5:
• Test Case 3: Expected 10, Actual 2 (Killed)
Mutant M5 is killed.
• M1: Killed
• M2: Not killed
• M3: Killed
• M4: Killed
• M5: Killed
Number of mutants killed = 4
Total number of mutants = 5
Mutation testing helps identify weak spots in the test suite, prompting the creation
of more effective tests to catch these bugs.
Mutation Testing
Types of Mutation Testing:
1) Value Mutations:
In this type of testing the values are changed to detect errors in the program. Basically a small value
is changed to a larger value or a larger value is changed to a smaller value. In this testing basically
constants are changed.
Initial Code:
int mod = 1000000007;
int a = 12345678;
int b = 98765432;
int c = (a + b) % mod;
Changed Code:
int mod = 1007;
int a = 12345678;
int b = 98765432;
int c = (a + b) % mod;
2. Decision Mutations:
In decision mutations logical or arithmetic operators are changed to detect errors in the
program.
Initial Code:
if(a < b)
c = 10;
else
c = 20;
Changed Code:
if(a > b)
c = 10;
else
c = 20;
3. Statement Mutations:
In statement mutations a statement is deleted or it is replaces by some other statement.
Initial Code:
if(a < b)
c = 10;
else
c = 20;
Changed Code:
if(a < b)
d = 10;
else
d = 20;
Walkthrough
Walkthroughs are informal meetings for evaluating and discussing the contents of
a software artifact (Ex. Requirements, design documents, code , test plans).
The walkthrough is a review meeting process but it is different from the
Inspection, as it does not involve any formal process.
They aim to identify defects, gather feedback, and improve the
quality of the product.
The walkthrough is started by the Author of the code.
In the walkthrough, the code or document is read by the author, and others who
are present in the meeting can note down the important points or can write notes
on the defects and can give suggestions about them.
Cont..
Key Points:
• Objective: Find defects early, understand the document/code, and
improve it.
• Participants: Author, peers, technical experts, stakeholders.
• Process: The author presents the artifact, and participants provide
feedback.
• Outcome: List of identified issues and suggestions for improvement.
Unit Test Assertions
class Calculator {
public int add(int a, int b) {
// Initially, this method does not exist or is empty
return 0;
}
}
Cont..
Step 2: Write the code to pass the test:
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
Cont..
Step 3: Refactor (if needed) and ensure the test passes:
@Test
void testAdd() {
Calculator calculator = new Calculator();
assertEquals(5, calculator.add(2, 3));
assertEquals(0, calculator.add(-1, 1));
assertEquals(0, calculator.add(0, 0));
}
}
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
Data Driven Unit Test Assertion
Data Driven Testing is a software testing method in which test data is stored in
table or spreadsheet format.
Data driven testing allows testers to input a single test script that can execute
tests for all test data from a table and expect the test output in the same table.
It is also called table-driven testing or parameterized testing.
A development team can save time and money by using Data driven testing.
We can reuse the test case as often as We like in other situations by altering its
parameters.
Example
@ParameterizedTest
@CsvSource({
"2, 3, 5",
"-1, 1, 0",
"0, 0, 0",
"10, -5, 5"
})
void testAdd(int a, int b, int expected) {
Calculator calculator = new Calculator();
assertEquals(expected, calculator.add(a, b));
}
}
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
Why Data Driven Testing?
Data Driven Testing is important because testers frequently have multiple data
sets for a single test and creating individual tests for each data set can be time-
consuming.
Data driven testing helps keeping data separate from test scripts and the same test
scripts can be executed for different combinations of input test data and test
results can be generated efficiently.
Data driven testing framework
Test Data: Information on the data needed for testing, including how it
will be created and managed
Tools: Any testing tools or utilities required for the testing process
Steps to set up
Test execution is the process of running the test cases and reporting the
results.
Components:
Test Scripts: Automated or manual scripts to be executed.
Test Schedule: Timing and sequencing of test case execution.
Execution Logs: Keeping logs of test execution for reference and
analysis.
Defect Reporting: Process for reporting and tracking defects found
during testing.
Steps to Execute
Revisions are changes made to the test plan or the testing process
based on the analysis of test results and feedback.
Components:
Feedback Loop: Incorporating feedback from the testing team and
stakeholders.
Continuous Improvement: Regularly updating and improving test
plans and processes.
Documentation Updates: Ensuring all documents are updated to
reflect changes.
Retesting: Executing tests again after changes to verify fixes.
Steps to Revise
Dropped
Pass %
Pass
Appeared
Registered
0 20 40 60 80 100 120