0% found this document useful (0 votes)
22 views209 pages

Python SDLC Stages and Models Guide

Uploaded by

Raja Meenakshi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views209 pages

Python SDLC Stages and Models Guide

Uploaded by

Raja Meenakshi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Module 1 - Software Development Life Cycle

1. Software Development Life cycle

The Software Development Life Cycle (SDLC) is a structured process followed during the
development of software applications. It is independent of the programming language used,
including Python. However, Python's flexibility and tools make implementing SDLC stages
efficient. Below is an outline of SDLC stages in the context of Python development:

1. Planning

●​ Define the scope, objectives, and feasibility of the project.


●​ Python Tools:
○​ Jupyter Notebooks for brainstorming and prototyping.
○​ Mind-mapping tools like XMind for outlining ideas.
●​ Deliverables: Project scope, budget, and timeline.

2. Requirement Analysis

●​ Gather and analyze requirements from stakeholders.


●​ Use-case scenarios are created.
●​ Python Tools:
○​ PyPDF2 or docx for handling requirement documents.
○​ SQLite or mock databases for testing data requirements.

3. Design

●​ Create high-level and detailed software designs, including architecture, database schema,
and UI/UX designs.
●​ Python Tools:
○​ UML Tools like PyUML for creating design diagrams.
○​ Libraries like SQLAlchemy for designing database schemas.
●​ Deliverables: Design documents, wireframes, and database schema.
4. Implementation (Coding)

●​ Translate the design into Python code.


●​ Use version control for collaboration.
●​ Python Tools:
○​ Flask or Django for web development.
○​ NumPy, Pandas, TensorFlow for data science and AI projects.
○​ Git/GitHub for version control.
●​ Deliverables: Functional Python modules and scripts.

5. Testing

●​ Test the software to identify and fix defects.


●​ Python Tools:
○​ unittest, pytest for automated unit and integration testing.
○​ selenium for testing web applications.
○​ mock library for simulating dependencies.
●​ Deliverables: Test cases, bug reports, and test results.

6. Deployment

●​ Deploy the software in the production environment.


●​ Python Tools:
○​ Docker for containerization.
○​ AWS, Google Cloud, or Azure SDKs for cloud deployment.
○​ Fabric or Ansible for automating deployment.
●​ Deliverables: Live system, deployment scripts.

7. Maintenance

●​ Monitor and update the software to fix bugs, improve performance, or add features.
●​ Python Tools:
○​ logging library for application monitoring.
○​ APScheduler or Celery for scheduling maintenance tasks.
○​ pip-tools for managing dependencies.
●​ Deliverables: Patches, updates, and documentation.

Python-Specific Practices for SDLC:

●​ Agile SDLC in Python: Python's readability and modularity align well with Agile
methodologies for iterative development.
●​ Documentation: Use tools like Sphinx to generate clear project documentation.
●​ Code Quality: Tools like flake8, pylint, and black ensure adherence to Python best
practices.

By following the SDLC in Python, developers can ensure efficient, high-quality software
development that meets user requirements and industry standards.

2. SDLC Models

The Software Development Life Cycle (SDLC) Models are frameworks that guide the
development process of software. Python, being versatile, supports the implementation of
various SDLC models. Below is an overview of popular SDLC models and how they apply to
Python projects:

1. Waterfall Model

●​ Description: Sequential process where each phase must be completed before moving to
the next.
●​ When to Use: For projects with well-defined and unchanging requirements.
●​ Python in Waterfall:
○​ Tools like Jupyter Notebooks or Google Docs can document requirements and
designs.
○​ Python's structured testing libraries (e.g., unittest) ensure proper testing at the
testing phase.
○​ Deployment handled by tools like Fabric or Docker.
2. Agile Model

●​ Description: Iterative and incremental approach emphasizing collaboration, flexibility,


and frequent deliveries.
●​ When to Use: For projects with evolving requirements and close customer involvement.
●​ Python in Agile:
○​ Frameworks like Flask or Django facilitate quick development of minimum
viable products (MVPs).
○​ Use pytest for test-driven development (TDD).
○​ Integration with Jira or Trello for sprint planning.
○​ Continuous integration using GitHub Actions or Jenkins.

3. Iterative Model

●​ Description: Develops software incrementally by refining the initial version in cycles.


●​ When to Use: When requirements are not well-defined initially but expected to evolve.
●​ Python in Iterative:
○​ Python's ease of prototyping with libraries like Tkinter for GUIs or Streamlit for
data apps.
○​ Refine code through pytest for regression testing after each iteration.

4. V-Model (Validation and Verification)

●​ Description: A variation of the Waterfall model with a strong focus on testing at every
stage.
●​ When to Use: For high-reliability systems (e.g., healthcare or defense).
●​ Python in V-Model:
○​ Automate unit tests with unittest.
○​ Perform system and integration tests with selenium or pytest.
○​ Use mock to simulate components during validation.
5. Spiral Model

●​ Description: Combines iterative development with risk analysis, involving multiple


cycles (spirals).
●​ When to Use: For large projects requiring risk assessment.
●​ Python in Spiral:
○​ Risk modeling with SciPy or NumPy.
○​ Iterative prototypes using frameworks like Django REST Framework.
○​ Cost estimation with Python-based tools like Openpyxl or spreadsheets.

6. Big Bang Model

●​ Description: A flexible model with minimal planning and emphasis on coding.


●​ When to Use: For small, research-focused projects with unclear requirements.
●​ Python in Big Bang:
○​ Rapid prototyping using Python REPL or Jupyter Notebooks.
○​ Quick fixes and iterations with Python's dynamic typing and interactive testing.

7. DevOps Model

●​ Description: Combines development and operations for continuous delivery and


integration.
●​ When to Use: For projects requiring fast deployment and frequent updates.
●​ Python in DevOps:
○​ Automate builds with Fabric, Ansible, or Terraform.
○​ Continuous testing using pytest integrated with CI/CD pipelines.
○​ Monitoring applications using Prometheus or Grafana SDKs.

8. Rapid Application Development (RAD)

●​ Description: Focuses on quick development and iterative user feedback.


●​ When to Use: When a quick delivery is prioritized over thorough planning.
●​ Python in RAD:
○​ Use Python frameworks like Flask for rapid prototyping.
○​ Interactive development with Streamlit or Dash for data-driven apps.
○​ Mock user interfaces with Python GUI libraries like PyQt.

Choosing the Right Model in Python:

●​ Stable Requirements: Use Waterfall or V-Model.


●​ Evolving Requirements: Use Agile, Iterative, or Spiral.
●​ Quick Prototyping: Use Big Bang or RAD.
●​ Continuous Delivery: Use DevOps.

Each model aligns well with Python's simplicity, readability, and rich ecosystem of libraries and
tools. Selecting the right SDLC model depends on project needs and constraints.

3. Waterfall vs Agile

Python's versatility makes it suitable for both Waterfall and Agile methodologies. Here's a
comparison of the two methodologies in the context of Python development:

1. Process Flow

Waterfall

●​ Linear and Sequential: Each phase (e.g., planning, design, development, testing) is
completed before moving to the next.
●​ Rigid Structure: Changes after a phase is completed are costly and time-consuming.

Agile

●​ Iterative and Incremental: Development occurs in cycles (sprints), delivering smaller,


functional modules.
●​ Flexible Structure: Allows frequent changes and adaptations based on user feedback.
Python Features Supporting Both:

●​ Waterfall: Python's simplicity and readability help ensure the design and implementation
follow a predetermined plan without rework.
●​ Agile: Python’s dynamic nature and rich library ecosystem enable quick prototyping and
iterative updates.

2. Development Speed

Waterfall

●​ Slower development, as no phase overlaps.


●​ Testing and feedback are delayed until the later stages.

Agile

●​ Faster development due to parallel phases (e.g., coding and testing occur in the same
sprint).
●​ Continuous feedback speeds up improvements.

Python Features Supporting Agile:

●​ Python’s frameworks like Flask or Django allow quick MVP development.


●​ Libraries like unittest and pytest integrate seamlessly into iterative testing.

3. Flexibility

Waterfall

●​ Inflexible: Requirements must be clearly defined upfront.


●​ Poor adaptability to changes during development.

Agile

●​ Highly flexible: Requirements can evolve, and priorities can shift mid-project.
●​ Ideal for projects with uncertain or changing requirements.
Python's Role:

●​ Agile workflows leverage Python's dynamic typing and ability to handle changes quickly,
while Waterfall benefits from Python's robustness for well-defined tasks.

4. Team Collaboration

Waterfall

●​ Communication is minimal and formal, often limited to phase transitions.


●​ Developers work independently on separate tasks.

Agile

●​ Encourages regular communication and collaboration (e.g., daily stand-ups, sprint


reviews).
●​ Promotes cross-functional teamwork.

Python Tools for Agile Collaboration:

●​ Jupyter Notebooks: Great for collaborative prototyping.


●​ Git/GitHub: Ensures real-time collaboration and version control.

5. Testing Approach

Waterfall

●​ Testing occurs after development is complete.


●​ Bugs found later in the cycle are harder and more expensive to fix.

Agile

●​ Continuous testing is integrated into each sprint.


●​ Early detection of bugs reduces costs and improves quality.
Python Testing Tools:

●​ Waterfall: Use unittest for structured, end-phase testing.


●​ Agile: Use pytest for TDD (Test-Driven Development) or BDD (Behavior-Driven
Development) in iterative cycles.

6. Deployment

Waterfall

●​ Single, large-scale deployment at the end of the project.


●​ Risk of delays due to late discovery of major issues.

Agile

●​ Frequent deployments, often at the end of each sprint.


●​ Reduces deployment risks and allows faster time-to-market.

Python Deployment Tools:

●​ Waterfall: Use Docker and Fabric for well-planned deployments.


●​ Agile: Use CI/CD pipelines with tools like GitHub Actions or Jenkins for continuous
delivery.

7. Use Cases

Waterfall

●​ Projects with clearly defined requirements and no anticipated changes.


●​ Examples: Legacy system upgrades, government projects, or compliance-driven
applications.

Agile

●​ Projects with dynamic requirements or those focused on user-centric design.


●​ Examples: Web applications, AI/ML prototypes, or startups needing rapid iterations.
Summary Table

Aspect Waterfall Agile

Process Flow Linear and sequential Iterative and incremental

Flexibility Rigid Highly flexible

Development Speed Slower Faster

Testing At the end Continuous

Deployment Single deployment Frequent, incremental deployments

Best for Fixed, well-defined projects Dynamic, evolving projects

Choosing Between Waterfall and Agile in Python

●​ Use Waterfall: If the project has fixed requirements, minimal risk of change, and strict
deadlines.
●​ Use Agile: If the project requires rapid iterations, frequent feedback, and continuous
improvement.

Python’s readability, extensive libraries, and tools like pytest, Flask, Docker, and GitHub make
it an excellent choice for both methodologies.

4. Software Testing Life Cycle

The Software Testing Life Cycle (STLC) is a systematic process followed to ensure the quality
of software. Python, with its vast ecosystem of libraries and tools, provides robust support for
implementing all stages of the STLC. Here's how Python integrates with the STLC:

1. Requirement Analysis

●​ Objective: Understand the testing requirements and identify the scope.


●​ Activities:
○​ Analyze software requirements to identify testable aspects.
○​ Identify the types of tests (functional, non-functional, security, etc.).
○​ Check for ambiguities or incomplete requirements.
●​ Python Tools:
○​ PyPDF2 or docx: Parse requirement documents.
○​ SQLite or mock databases: Test database-specific requirements.
○​ Create requirement traceability matrices with Python.

2. Test Planning

●​ Objective: Define the test strategy, test plan, and resource allocation.
●​ Activities:
○​ Identify tools, frameworks, and timelines.
○​ Allocate roles and responsibilities to the testing team.
○​ Estimate testing effort and costs.
●​ Python Tools:
○​ Jira-Python API: Manage test plans and tasks.
○​ Python-based automation tools like Selenium for planning automation efforts.

3. Test Case Development

●​ Objective: Create detailed test cases and prepare test data.


●​ Activities:
○​ Write manual and automated test cases.
○​ Prepare input data and expected outputs.
○​ Develop reusable test scripts.
●​ Python Tools:
○​ Use unittest or pytest for writing test cases.
○​ Create test data using libraries like Faker or Pandas.
○​ Mock external systems using mock or responses.
4. Test Environment Setup

●​ Objective: Prepare the environment where testing will be conducted.


●​ Activities:
○​ Configure hardware, software, and network settings.
○​ Deploy test builds in the staging environment.
○​ Verify environment readiness.
●​ Python Tools:
○​ Automate setup using Fabric or Ansible.
○​ Use Docker for containerized environments.
○​ Test environment monitoring with psutil.

5. Test Execution

●​ Objective: Execute test cases and report bugs.


●​ Activities:
○​ Execute manual and automated test cases.
○​ Log defects and track their resolution.
○​ Perform regression testing for bug fixes.
●​ Python Tools:
○​ Automate testing with pytest, unittest, or Selenium for web apps.
○​ Log defects using Python APIs for Bugzilla or Jira.
○​ Run performance tests using Locust or JMeter.

6. Test Closure

●​ Objective: Evaluate and summarize the testing process.


●​ Activities:
○​ Document test results and provide test metrics.
○​ Conduct test closure meetings to analyze lessons learned.
○​ Archive test artifacts for future reference.
●​ Python Tools:
○​ Generate reports using Allure or pytest-html.
○​ Summarize test coverage with [Link].
○​ Store test logs and reports in databases using SQLAlchemy.

Python-Specific Advantages in STLC

1.​ Readability: Python's simple syntax allows for clear test scripts and documentation.
2.​ Automation-Friendly: Python integrates seamlessly with automation frameworks like
Selenium, Appium, and Robot Framework.
3.​ Rich Ecosystem:
○​ Testing libraries: pytest, unittest, doctest.
○​ Performance testing: Locust, Taurus.
○​ Security testing: Bandit, OWASP ZAP API.
4.​ Cross-Platform: Python works across Windows, macOS, and Linux, ensuring consistent
testing environments.

Summary Table of STLC in Python

Stage Objective Python Tools

Requirement Analysis Understand testable requirements PyPDF2, SQLite, Pandas

Test Planning Define strategy, resources, and Jira-Python API, Selenium


timelines

Test Case Create and automate test cases unittest, pytest, Faker, mock
Development

Test Environment Configure and verify testing Docker, Fabric, Ansible,


Setup environment psutil

Test Execution Execute tests and log defects pytest, Selenium, Jira API

Test Closure Document results and lessons Allure, pytest-html,


learned [Link]
By following the STLC with Python's tools and libraries, software teams can ensure a thorough
and efficient testing process, leading to high-quality software delivery.

5. Requirement Gathering and Analysis

Requirement Gathering and Analysis is the initial phase of the Software Development Life
Cycle (SDLC) where the functional, non-functional, and business requirements are collected,
analyzed, and documented. Python can facilitate this phase with its powerful libraries and tools.

Steps in Requirement Gathering and Analysis Using Python

1. Gathering Requirements

This involves collecting information from stakeholders through interviews, surveys, and
document analysis.

●​ Activities:
○​ Conduct interviews or meetings with stakeholders.
○​ Use questionnaires or surveys to gather user expectations.
○​ Analyze existing systems and documentation.
●​ Python Tools and Libraries:
○​ OpenPyXL or Pandas: To parse and analyze Excel sheets or tabular data
containing requirements.
○​ NLTK (Natural Language Toolkit): For processing textual data from interviews or
survey results.
○​ SpeechRecognition: To convert spoken requirements into text from recorded
meetings or discussions.

Example:

import speech_recognition as sr

recognizer = [Link]()
with [Link]('meeting_audio.wav') as source:
audio = [Link](source)
text = recognizer.recognize_google(audio)
print("Transcribed Text: ", text)

2. Organizing Requirements

This step involves structuring the collected data for clarity and traceability.

●​ Activities:
○​ Categorize requirements as functional, non-functional, or business.
○​ Prioritize requirements based on stakeholder needs.
●​ Python Tools and Libraries:
○​ Pandas: To create and manage requirement traceability matrices.
○​ Matplotlib or Seaborn: To visualize priority or category-based distributions.

Example:

import pandas as pd

data = {
"Requirement": ["Login", "Data Encryption", "Generate
Reports"],
"Category": ["Functional", "Non-Functional", "Functional"],
"Priority": ["High", "Medium", "Low"]
}
df = [Link](data)
print(df)

3. Analyzing Requirements

This involves assessing the feasibility, completeness, and clarity of the requirements.
●​ Activities:
○​ Identify ambiguities or conflicts in requirements.
○​ Check the technical feasibility of each requirement.
○​ Validate requirements against business goals.
●​ Python Tools and Libraries:
○​ spaCy or TextBlob: For analyzing textual requirements to identify ambiguities.
○​ NumPy: For performing feasibility calculations on numerical data.

Example:

from textblob import TextBlob

requirement = "The system should be user-friendly and secure."


blob = TextBlob(requirement)
print("Sentiment Analysis: ", [Link])

4. Documenting Requirements

Document the finalized requirements for reference and approval.

●​ Activities:
○​ Create Software Requirement Specification (SRS) documents.
○​ Include use cases, diagrams, and acceptance criteria.
●​ Python Tools and Libraries:
○​ docx: To automate the creation of SRS documents.
○​ matplotlib or Graphviz: To generate visualizations like flowcharts or UML
diagrams.

Example:

from docx import Document

doc = Document()
doc.add_heading("Software Requirement Specification (SRS)",
level=1)
doc.add_paragraph("1. Introduction")
doc.add_paragraph("The system will provide a secure and
user-friendly experience.")
[Link]("[Link]")

5. Managing Requirements

Track and update requirements throughout the project lifecycle.

●​ Activities:
○​ Manage requirement changes.
○​ Maintain a history of modifications.
●​ Python Tools and Libraries:
○​ SQLite: To store and track requirement versions.
○​ GitPython: For version control of requirement documents.

Example:

import sqlite3

conn = [Link]('[Link]')
cursor = [Link]()

[Link]('''
CREATE TABLE IF NOT EXISTS requirements (
id INTEGER PRIMARY KEY,
description TEXT,
category TEXT,
priority TEXT
)
''')

[Link]('''
INSERT INTO requirements (description, category, priority)
VALUES ('Login Feature', 'Functional', 'High')
''')

[Link]()
[Link]()

Benefits of Using Python for Requirement Gathering and Analysis

1.​ Automation: Python can automate repetitive tasks, like transcription, analysis, and report
generation.
2.​ Data Processing: Libraries like Pandas and NumPy streamline data manipulation.
3.​ Visualization: Tools like Matplotlib and Seaborn provide insights through graphs.
4.​ Integration: Python can interface with APIs and tools like Jira or Trello for efficient
tracking.

By leveraging Python’s tools and libraries, the requirement gathering and analysis phase
becomes more efficient, organized, and adaptable, ensuring clear and actionable project
deliverables.
Module 2 - Introduction to Manual Testing
1. Introduction to Software Testing

Software testing in Python is a critical part of the software development process that ensures the
quality and reliability of your code. Python provides a variety of tools and frameworks to support
both manual and automated testing. Here's an introduction to key concepts and testing
approaches in Python:

1. Types of Testing

●​ Unit Testing: This focuses on testing individual components (usually functions or


methods) in isolation.
●​ Integration Testing: Tests the interaction between different modules or services.
●​ Functional Testing: Ensures that the system performs as expected according to the
requirements.
●​ System Testing: Validates the complete system's behavior, often in an environment
similar to production.
●​ Regression Testing: Ensures new code changes do not break existing functionality.

2. Python Testing Libraries

●​ unittest: Python's built-in library for unit testing.


○​ It includes features like test discovery, test case classes, assertions, and test
runners.

Example:​
import unittest

def add(a, b):


return a + b

class TestAddition([Link]):
def test_add(self):
[Link](add(1, 2), 3)

if __name__ == "__main__":
[Link]()

●​ pytest: A more powerful, flexible, and user-friendly testing framework.


○​ Supports fixtures, parametrization, and advanced assertions.

Example:​
def add(a, b):
return a + b

def test_add():
assert add(1, 2) == 3

●​ nose2: A testing framework that extends unittest with additional features, including
test discovery and plugins.
●​ doctest: Checks if the documentation examples in Python docstrings are correct by
running them as tests.

3. Test-Driven Development (TDD)

●​ In TDD, you write tests before writing the code that satisfies them.
●​ This approach encourages small, incremental changes and helps ensure that code meets
specifications from the outset.
●​ Example cycle:
1.​ Write a test.
2.​ Run the test (it should fail).
3.​ Write just enough code to pass the test.
4.​ Refactor code and rerun tests.
4. Mocking

●​ Mocking helps isolate parts of the code that interact with external systems (like
databases, APIs) during testing.
●​ Python’s [Link] module allows for creating mock objects.

Example:​
from [Link] import MagicMock

def get_user_data(api):
return api.fetch_data()

mock_api = MagicMock()
mock_api.fetch_data.return_value = {'name': 'John Doe'}
assert get_user_data(mock_api) == {'name': 'John Doe'}

5. Test Coverage

●​ Test coverage measures how much of the code is tested by your test cases.
●​ Tools like [Link] can help track this metric and generate reports.

Example command:​
coverage run -m unittest discover
coverage report

6. Continuous Integration (CI) and Testing

●​ Tools like Travis CI, GitHub Actions, or Jenkins can be integrated with your testing
suite to automatically run tests on every code push or pull request.
●​ This ensures that code quality is maintained over time.
Conclusion

Software testing is a fundamental practice to ensure the correctness, reliability, and quality of
your Python applications. By leveraging the power of Python testing libraries such as
unittest, pytest, and nose2, along with best practices like TDD, mocking, and test
coverage, you can significantly reduce the risk of defects and improve the maintainability of
your code.

2. Role of a Tester

The role of a tester is crucial in the software development process, as they are responsible for
ensuring that the software meets the required standards of quality, functionality, and performance
before it is released. Testers help identify bugs, usability issues, and areas where the software can
be improved. Here's a breakdown of a tester's role:

1. Test Planning

●​ Requirement Analysis: A tester reviews the functional and non-functional requirements


to understand what needs to be tested and what the expected behavior of the system is.
●​ Test Strategy: Define the approach for testing the software, including which types of
testing will be performed (e.g., functional, regression, performance testing).
●​ Test Plan Creation: Create a detailed test plan that outlines the scope of testing,
resources needed, schedule, testing methods, and risk management strategies.

2. Test Case Design

●​ Test Case Development: Based on the requirements, a tester creates test cases that
describe specific scenarios to verify the software's functionality.
●​ Test Data Preparation: Prepare the necessary data for testing, including valid, invalid,
boundary, and edge cases.
●​ Test Coverage: Ensure that the tests cover all aspects of the system, including positive
and negative scenarios.
3. Test Execution

●​ Manual Testing: Perform testing manually, interacting with the system directly to verify
that it behaves as expected. This includes UI testing, functional testing, and exploratory
testing.
●​ Automated Testing: Write and execute automated test scripts to validate functionality,
especially for repetitive tasks like regression testing or load testing.
●​ Regression Testing: Re-run existing test cases whenever there is a change in the software
(e.g., after new features are added or bugs are fixed) to ensure that existing functionality
is not broken.

4. Bug Reporting and Documentation

●​ Defect Reporting: When a defect or bug is identified, the tester logs it with clear and
detailed steps to reproduce, along with the expected vs. actual behavior.
●​ Bug Tracking: Use bug tracking tools (e.g., Jira, Bugzilla) to manage and track defects
and ensure they are resolved.
●​ Test Results Reporting: Provide detailed reports on the testing results, including the
number of passed and failed test cases, severity of defects, and test coverage.

5. Collaboration

●​ Communication with Developers: Testers work closely with developers to clarify


requirements, understand the architecture, and reproduce and resolve defects.
●​ Stakeholder Interaction: Testers may interact with stakeholders (e.g., product managers,
business analysts) to ensure that the software meets business requirements and user
expectations.
●​ Feedback Loops: Provide feedback to the development team on software quality and
usability, and suggest improvements or optimizations.
6. Test Environment Setup

●​ Test Environment Configuration: Ensure that the testing environment mimics


production as closely as possible, with the necessary hardware, software, and network
configurations.
●​ Test Data Management: Create or manage test data that is used to simulate various user
scenarios and ensure that the system behaves as expected under different conditions.

7. Performance Testing

●​ Load and Stress Testing: Test how the system behaves under heavy loads or stress to
ensure that it performs well under expected user traffic.
●​ Scalability Testing: Ensure that the system can handle increased usage and data over
time.

8. User Experience (UX) Testing

●​ Usability Testing: Ensure that the software is user-friendly and intuitive. Testers often
perform manual testing on the user interface to check if it aligns with the design and user
expectations.
●​ Accessibility Testing: Verify that the software is accessible to users with disabilities
(e.g., through screen readers or keyboard navigation).

9. Test Automation (Optional but Valuable)

●​ Automated Test Scripts: Create and maintain automated tests to speed up the testing
process, especially for repetitive tasks.
●​ Tool Usage: Familiarity with test automation tools like Selenium, Appium, or
TestComplete helps testers build robust automated test suites.
10. Continuous Improvement

●​ Test Process Improvement: Review and refine the testing processes to make them more
efficient and effective. This can involve adopting new tools, practices, or methodologies
like Agile or DevOps.
●​ Learning and Upskilling: Stay updated with new testing techniques, tools, and industry
trends to improve the overall quality of testing and contribute to the growth of the team.

Key Skills for Testers:

●​ Analytical Skills: Ability to analyze requirements and identify potential issues or edge
cases.
●​ Attention to Detail: Spotting inconsistencies, discrepancies, or flaws in functionality.
●​ Communication Skills: Writing clear test cases, defect reports, and test results, and
effectively communicating with stakeholders.
●​ Technical Proficiency: Knowledge of programming languages (e.g., Python, Java) for
automation and understanding the technical architecture of the software.
●​ Knowledge of Testing Tools: Familiarity with testing frameworks (e.g., Selenium, JUnit,
TestNG), bug tracking tools (e.g., Jira), and CI/CD systems.
●​ Problem-Solving: Ability to identify, isolate, and troubleshoot issues in complex
software systems.

Conclusion:

A tester plays an essential role in ensuring the quality of software by performing comprehensive
testing activities, reporting defects, and working closely with developers and stakeholders. They
are responsible for preventing defects, verifying functionality, and ensuring the system works as
intended for end users. Testers help improve software reliability, usability, and performance,
ultimately contributing to the success of a product.
3. What is defect, Quality, expected result = actual result

In the context of software testing, the terms defect, quality, and expected result = actual result
have specific meanings. Here's how these concepts relate to Python testing:

1. Defect

●​ Definition: A defect is an issue or bug in the software where it does not behave as
expected or fails to meet the specified requirements. It can arise from incorrect code,
miscommunication in requirements, or unexpected interactions between different
components of the system.
●​ In Python Testing: During Python testing (using libraries like unittest, pytest,
etc.), a defect is often identified when the actual result of a test case doesn't match the
expected result.

Example:​
def add(a, b):
return a + b

def test_add():
assert add(1, 2) == 3 # This passes, no defect

# If the code was incorrect and returned 4 instead of 3, it


would be a defect.
assert add(1, 2) == 4 # This would fail, indicating a
defect in the code

2. Quality

●​ Definition: Quality in software refers to how well the software meets the requirements,
user needs, and industry standards. It involves the correctness, performance, security,
usability, and maintainability of the software.
●​ In Python Testing: Quality is measured through successful tests and by ensuring that the
software behaves correctly, is easy to use, performs efficiently, and is free of defects.
High-quality code often results from comprehensive unit tests, integration tests, and
thorough bug fixing.
○​ Python tools like pytest can help ensure quality by running tests efficiently and
allowing for assertions that check various conditions in the software.

Example:​
def multiply(a, b):
return a * b

def test_multiply():
assert multiply(2, 3) == 6 # This helps ensure the function
works correctly
assert multiply(-2, 3) == -6 # Checks negative numbers

3. Expected Result = Actual Result

●​ Definition: In software testing, the expected result is what you anticipate the software
will do under certain conditions. The actual result is what the software actually does
when executed. A defect occurs if the expected result does not match the actual result.
●​ In Python Testing: When writing tests in Python, you define the expected result and
compare it with the actual result generated by the function. If they match, the test passes;
if they don't, the test fails and a defect is identified.

Example:​
def subtract(a, b):
return a - b

def test_subtract():
expected_result = 5
actual_result = subtract(10, 5)

assert expected_result == actual_result # If they match,


the test passes

Mismatch Example (Defect):​


def subtract(a, b):
return a + b # Defective code, it should subtract

def test_subtract():
expected_result = 5
actual_result = subtract(10, 5)

assert expected_result == actual_result # This will fail


because the actual result is 15, not 5

Summary:

●​ Defect: When the actual result does not match the expected result.
●​ Quality: The overall condition of the software, typically validated through testing to
ensure correctness, performance, security, and user experience.
●​ Expected Result = Actual Result: In testing, this is the goal. When the expected and
actual results match, the software works as expected, indicating no defects. If they don't
match, it points to a defect that needs to be addressed.

In Python, tools like unittest, pytest, and assertions help automate this process to ensure
that the software functions as expected and meets quality standards.
4. Seven Principles of Testing

The Seven Principles of Testing are fundamental guidelines that help ensure effective and
efficient software testing. These principles apply regardless of the programming language used,
including Python. Here's an overview of the Seven Principles of Testing with examples from
Python testing:

1. Testing Shows the Presence of Defects

●​ Principle: Testing can only show the presence of defects, not their absence. No matter
how many tests you run, you cannot prove that there are no defects; you can only detect
defects that are present.
●​ In Python: When running tests, if they pass, it shows that the code works correctly for
the tested scenarios, but it doesn't guarantee that there are no defects in other untested
parts of the code.

Example:​
def multiply(a, b):
return a * b

def test_multiply():
assert multiply(2, 3) == 6 # No defect found in this test
case
# Even though this test passes, there could be defects in other
parts of the software.

2. Exhaustive Testing Is Impossible

●​ Principle: It is impossible to test all possible input combinations and scenarios,


especially for complex software. Instead, you must select a representative set of tests that
cover critical paths, edge cases, and typical user behaviors.
●​ In Python: Focus on test cases that represent real-world usage, edge cases, and boundary
conditions, as it's impractical to test every combination.

Example:​
def add(a, b):
return a + b

def test_add():
assert add(0, 0) == 0 # Testing edge case (zero)
assert add(-1, 1) == 0 # Testing negative and positive
number
# Testing all combinations of a and b is impractical

3. Early Testing

●​ Principle: The earlier testing begins, the cheaper it is to fix defects. Ideally, testing
should start as soon as the first piece of code is available, even before the final code is
completed.
●​ In Python: By practicing Test-Driven Development (TDD), tests are written before
code, allowing early detection of defects and ensuring that the software meets
requirements from the start.

Example (TDD):​
# Step 1: Write a failing test first
def test_add():
assert add(1, 2) == 3 # This will fail if 'add' is not
implemented yet

# Step 2: Write just enough code to pass the test


def add(a, b):
return a + b

# Step 3: Refactor if necessary

4. Defects Clustering

●​ Principle: Defects tend to be clustered in certain areas of the software, such as complex
logic or new code. A few modules may have the majority of defects.
●​ In Python: Focus more intensive testing on high-risk areas, such as newly developed
features or complex parts of the codebase.

Example:​
def complex_function(x, y):
return x ** y # Complex calculation

def test_complex_function():
assert complex_function(2, 3) == 8 # Focus testing on more
complex parts

5. Testing Is Context Dependent

●​ Principle: The approach to testing depends on the context, such as the software's
intended use, development methodology, and environment. Testing for a web application
differs from testing for embedded systems.
●​ In Python: Choose testing approaches based on the type of software you are working on
(e.g., web apps, APIs, or machine learning models). For example, pytest may be great for
unit tests in Python, but Selenium is used for testing web applications.

Example (Web Testing):​


from selenium import webdriver

def test_login():
driver = [Link]()
[Link]("[Link]
assert [Link] == "Login Page"
[Link]()

6. Absence of Errors Is Not Proof of Correctness

●​ Principle: Just because no errors are detected during testing doesn't mean the software is
functioning correctly. It could still fail under certain conditions that have not been tested.
●​ In Python: If all tests pass, it only means the code works for the specific cases tested.
Additional testing is needed to ensure comprehensive coverage, and manual tests may
still uncover issues not addressed by automated tests.

Example:​
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b

def test_divide():
assert divide(6, 2) == 3 # Test case passes
# Absence of errors doesn't prove the code is correct for
all edge cases
assert divide(6, 0) # Raises ValueError, but no tests for
negative numbers or large inputs

7. Random Testing

●​ Principle: Random testing involves providing random inputs to the software and
observing its behavior. This can sometimes uncover defects that are not immediately
obvious.
●​ In Python: Tools like random or fuzz testing frameworks can be used to randomly test
different input combinations to help discover defects.

Example (Random Testing):​


import random

def random_test():
a = [Link](1, 100)
b = [Link](1, 100)
assert add(a, b) == a + b # Random values for input

random_test() # Run the test

Summary of the Seven Principles of Testing:

1.​ Testing shows the presence of defects: Testing can only identify defects, not prove their
absence.
2.​ Exhaustive testing is impossible: It's impossible to test every scenario, so focus on
critical paths and edge cases.
3.​ Early testing: Start testing early in the development process to detect defects sooner.
4.​ Defects clustering: Most defects tend to be concentrated in specific areas of the software.
5.​ Testing is context-dependent: The approach to testing should vary depending on the
software's type and context.
6.​ Absence of errors is not proof of correctness: Just because no errors are found doesn't
mean the software is working correctly in all cases.
7.​ Random testing: Random inputs can sometimes reveal defects that might not be
identified by regular test cases.

By applying these principles to your Python testing efforts, you can improve your testing
processes and ensure more reliable, high-quality software.
5. Verification vs Validation

In software testing, verification and validation are two distinct processes that help ensure the
software meets its requirements and performs as expected. Both are crucial to software quality,
and while they overlap in some ways, they serve different purposes. Here's a breakdown of the
two concepts in the context of Python testing:

1. Verification

●​ Definition: Verification is the process of evaluating whether the software meets the
specified requirements and design specifications. It ensures that the system is built
according to the intended design and that the code performs its intended functions
correctly in terms of logic and structure.
●​ Key Question: Are we building the product right?
●​ In Python Testing: Verification involves checking if the software's behavior aligns with
the technical specifications, such as running unit tests, checking for code correctness, and
ensuring that the code follows the defined structure.
●​ Example:

Writing unit tests in Python to ensure that individual functions behave as expected:​
def add(a, b):
return a + b

def test_add():
assert add(2, 3) == 5 # This is a verification test for
correctness of the 'add' function

○​ Ensuring that the code follows the design principles, for example, checking if the
functions or methods are implemented according to the design document or
specification.
2. Validation

●​ Definition: Validation is the process of ensuring that the software meets the business
needs and the requirements of the end-users. It checks if the software fulfills its intended
purpose and if it works in real-world scenarios.
●​ Key Question: Are we building the right product?
●​ In Python Testing: Validation involves testing the system as a whole, ensuring that the
software behaves correctly in real-world conditions. This might include integration tests,
acceptance tests, and manual or automated testing to simulate user behavior and confirm
that the system meets the user's needs.
●​ Example:

Running integration tests or acceptance tests to validate that the Python application as a whole
works correctly in a real-world context:​
def test_system_integration():
# Simulate a real-world scenario, such as user login or data
retrieval
user = login_user('user@[Link]', 'password123')
assert user is not None # Validating that the login
functionality meets user expectations

def test_acceptance():
# Verify end-to-end flow of a user registering and
submitting a form
assert form_submission('user@[Link]', 'password123') ==
'Success'
Key Differences Between Verification and Validation:

Aspect Verification Validation

Definition Ensuring the software is built correctly Ensuring the software meets business
based on specifications. needs and user expectations.

Focus Focuses on the correctness of the code and Focuses on the software's functionality
design. from the user's perspective.

Stage in Performed during development, often early. Performed after development, before or
Development after deployment.

Method Code reviews, unit testing, static analysis, User acceptance testing (UAT), system
inspection. testing, integration testing.

Objective To ensure the product is being built To ensure the product is solving the right
correctly. problem and meeting user needs.

Examples Unit tests, code reviews, static analysis, User acceptance testing, system testing,
integration checks. end-to-end testing.

Examples in Python:
Verification Example (Checking if the implementation is correct):​
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b

def test_divide():
assert divide(6, 3) == 2 # Verify the logic is correct
(Verification)
assert divide(6, 0) # This would raise ValueError, which is
expected behavior
Validation Example (Ensuring the software meets user needs):​
def test_user_login():
user = login_user('user@[Link]', 'password123')
assert user is not None # Validate that user login works
from the user's perspective

def test_registration_form():
response = submit_registration_form('user@[Link]',
'password123', 'John Doe')
assert response == "Success" # Validate that registration
meets user expectations

Summary:

●​ Verification is about ensuring that the software was built correctly according to the
design specifications and coding standards. It involves activities like unit testing, code
reviews, and static analysis.
●​ Validation is about ensuring that the software meets the business requirements and works
as expected from the end-user’s perspective. It includes activities like user acceptance
testing, system testing, and real-world scenario testing.

Both verification and validation are crucial for ensuring that a software product is both
functional and reliable, especially in Python-based applications where automated testing is a
powerful tool for both activities.
6. Flow of Manual Testing and Automation Testing

Both manual testing and automation testing follow systematic processes to ensure that
software functions as expected. Here's a breakdown of the flow for each testing approach,
specifically in the context of Python.

Manual Testing Flow

Manual testing involves human testers executing test cases without the assistance of automated
tools. It is primarily used for exploratory, usability, or ad-hoc testing. The flow is as follows:

1.​ Requirement Analysis


○​ Action: Understand the application requirements, user stories, and acceptance
criteria.
○​ Tools: Documents, requirement specification sheets, user stories.
○​ Example: A Python web application that accepts user input and displays results.
2.​ Test Planning
○​ Action: Create a test plan, identifying test cases, testing approach, testing
environment, and resource allocation.
○​ Tools: Test management tools (e.g., TestRail, Jira).
○​ Example: Test plan for verifying user authentication in the Python web
application.
3.​ Test Case Design
○​ Action: Write detailed test cases that specify the test steps, expected results, and
pass/fail criteria.
○​ Tools: Test case management tools, spreadsheets.
○​ Example: Test case for user login:
■​ Input: Correct username and password.
■​ Expected result: Successful login.
■​ Input: Incorrect username or password.
■​ Expected result: Error message displayed.
4.​ Test Environment Setup
○​ Action: Prepare the testing environment, which includes setting up the hardware,
software, databases, and any dependencies required for testing.
○​ Tools: Virtual environments, Python dependencies (e.g., virtualenv, pip).
○​ Example: Setting up a Python environment with Flask, SQLite, and pytest for
testing the Python web app.
5.​ Test Execution
○​ Action: Execute the test cases manually by interacting with the application and
recording the results. The tester manually verifies if the software behaves as
expected.
○​ Tools: Python app, test cases, browsers, etc.
○​ Example: A tester manually enters valid and invalid credentials into the login
form and checks if the expected results are returned.
6.​ Defect Reporting
○​ Action: If a test case fails, report the defect with all necessary details like steps to
reproduce, expected vs. actual result, and any error messages.
○​ Tools: Bug tracking tools (e.g., Jira, Bugzilla).
○​ Example: A failed login test where the system incorrectly logs in a user with
invalid credentials.
7.​ Retesting and Regression Testing
○​ Action: After a defect is fixed, retest the functionality and perform regression
testing to ensure the fix hasn't broken other parts of the application.
○​ Tools: Manual testing, tracking tools.
○​ Example: Retesting the login feature after a bug fix and verifying that other parts
of the application still function as expected.
8.​ Test Closure
○​ Action: After executing all test cases and validating results, conclude testing by
reporting test results, lessons learned, and the final test report.
○​ Tools: Test management tools, reports.
○​ Example: A report showing the status of each test case (pass/fail) and a summary
of the defects found.
Automation Testing Flow

Automation testing involves using scripts and tools to automatically execute test cases, often
saving time and ensuring repeatability. The flow is as follows:

1.​ Requirement Analysis


○​ Action: Understand the requirements and the areas where automation will be
beneficial.
○​ Tools: Requirement documents, user stories, automation feasibility analysis.
○​ Example: Identifying repetitive tasks like form submission in a Python web app
as candidates for automation.
2.​ Test Planning and Tool Selection
○​ Action: Create a test plan, decide on the tools and frameworks to use, and
determine the scope of automation.
○​ Tools: pytest, Selenium, unittest, Robot Framework.
○​ Example: Choose pytest for unit testing and Selenium for end-to-end web
automation testing in Python.
3.​ Test Case Design
○​ Action: Write test scripts or select existing test cases to be automated. These
scripts should cover the desired functionality.
○​ Tools: Python scripts with frameworks like unittest or pytest.

Example: Automating a login test case using Selenium:​


from selenium import webdriver

def test_login():
driver = [Link]()
[Link]("[Link]

driver.find_element_by_id("username").send_keys("user@[Link]
m")
driver.find_element_by_id("password").send_keys("password123")
driver.find_element_by_id("login_button").click()
assert [Link] == "Dashboard" # Validate login success
[Link]()

4.​ Test Environment Setup


○​ Action: Set up an automated testing environment, which may include configuring
test servers, setting up CI/CD pipelines, and managing test data.
○​ Tools: Jenkins, Docker, pytest, unittest, virtualenv.
○​ Example: Set up a CI pipeline with Jenkins to automatically run Python tests
whenever code is pushed to the repository.
5.​ Test Execution
○​ Action: Run the automated tests on the target environment. The tests will execute
without human intervention, and the results will be recorded.
○​ Tools: pytest, unittest, Selenium, CI/CD tools.

Example: Triggering a pytest run on a Python codebase using Jenkins:​


pytest --maxfail=3 --disable-warnings --tb=short

6.​ Defect Reporting


○​ Action: If an automated test fails, the defect is reported, often with detailed logs,
screenshots, or video captures of the failure.
○​ Tools: CI/CD integration, test reporting tools like Allure, Jenkins.
○​ Example: After a failed test, Jenkins reports the failure with logs and error
messages, allowing the developer to fix the issue.
7.​ Retesting and Regression Testing
○​ Action: Once defects are fixed, rerun the automated tests to verify that the issue is
resolved and that no new issues were introduced.
○​ Tools: Automation tools (e.g., pytest, Selenium), CI/CD pipelines.
○​ Example: After fixing a login bug, rerun the test_login() automation script
to ensure the login issue is resolved.
8.​ Test Maintenance
○​ Action: Regularly update the automated test scripts to accommodate changes in
the application, including updates to features and functionality.
○​ Tools: Version control systems (e.g., Git), test automation tools.
○​ Example: If the login form changes, the automated script should be updated to
reflect the new IDs or elements in the HTML.
9.​ Test Closure
○​ Action: Once the automated tests are consistently passing and providing value,
the testing cycle concludes. Results are reported, and feedback is collected.
○​ Tools: Test management tools, CI tools (e.g., Jenkins).
○​ Example: A final report from Jenkins that shows the test results and any failed
tests, along with logs and screenshots for review.

Key Differences Between Manual and Automation Testing Flow:

Aspect Manual Testing Automation Testing

Test Execution Performed by human testers. Executed by test scripts/tools.

Setup Requires manual configuration of test Environment setup is automated (via


environment. CI/CD).

Test Design Test cases written and executed Test scripts written and executed
manually. automatically.

Test Execution Time-consuming and may require Faster, especially for repetitive tasks.
Time repetition.

Flexibility More flexible for exploratory and Best for repetitive, regression, and
ad-hoc testing. performance testing.
Cost High cost in terms of time and effort Initial high cost for script creation but low
for repetitive tasks. cost for subsequent runs.

Maintenance Test cases need to be manually Test scripts need maintenance as the
updated. application changes.

Conclusion:

●​ Manual Testing is suitable for smaller, exploratory tests or scenarios where human
intuition is needed. It’s slower but useful for scenarios where automation would be too
costly or unnecessary.
●​ Automation Testing is ideal for repetitive, large-scale, and regression tests. It’s faster,
more scalable, and helps with continuous integration, but it requires an upfront
investment in creating test scripts and maintaining them as the software evolves.

For Python, automation tools like pytest, Selenium, and unittest are commonly used
for streamlining the testing process, while manual testing is used for specific cases where human
involvement is critical.
Module 3 - Types of Testing
1. Testing techniques
a)​ Reviews and Types
1. Testing Techniques

Testing techniques help ensure software quality by verifying that code behaves as expected.
Some common types:

a. Unit Testing

●​ Focus: Tests individual units or components of the code.


●​ Tool: unittest (built-in Python library).
●​ Example:

import unittest
def add(a, b):
return a + b
class TestMathOperations([Link]):
def test_add(self):
[Link](add(2, 3), 5)
[Link](add(-1, 1), 0)
if __name__ == "__main__":
[Link]()

b. Integration Testing

●​ Focus: Tests combined components to ensure they work together.


●​ Example: Testing a database connection with business logic.

c. Functional Testing

●​ Focus: Verifies software functionalities against requirements.


●​ Tool: pytest or behave (for Behavior Driven Development).

d. Regression Testing

●​ Focus: Ensures new changes don't break existing functionality.


●​ Technique: Use a suite of previously passed tests.

e. Load/Performance Testing

●​ Focus: Checks the application’s performance under heavy loads.


●​ Tool: Libraries like locust or pytest-benchmark.

2. Reviews in Software Testing

Reviews are static testing techniques where the code is examined without execution.

Types of Reviews

●​ a. Informal Reviews
○​ Purpose: Quick checks for obvious issues.
○​ Example: Pair programming discussions.
●​ b. Walkthrough
○​ Purpose: Explains code to a team for feedback.
○​ Example: Reviewing a new algorithm with peers.
●​ c. Technical Reviews
○​ Purpose: Conducted by technical experts.
○​ Example: Reviewing architecture documents or modules.
●​ d. Inspection
○​ Purpose: A formal process with defined roles and checklists.
○​ Example: Analyzing code for compliance with standards.

3. Automated Testing Frameworks in Python

a. pytest
●​ Versatile and widely used.
●​ Supports parameterized testing and fixtures.
●​ Example:

import pytest
@[Link]("a, b, expected", [(1, 2, 3), (-1, -1,
-2)])
def test_add(a, b, expected):
assert a + b == expected

b. unittest

●​ Built into Python for unit testing.

c. behave

●​ For Behavior Driven Development (BDD).


●​ Example:

Feature: Add numbers


Scenario: Adding two numbers
Given I have numbers 1 and 2
When I add them
Then the result should be 3

d. mock

●​ For mocking dependencies during testing.


●​ Example:

from [Link] import MagicMock

database = MagicMock()
database.get_data.return_value = {"name": "Test"}
assert database.get_data() == {"name": "Test"}

e. nose2

●​ Successor to nose, offering test discovery and execution.

Summary

●​ Testing Techniques: Unit, Integration, Functional, Regression, Performance.


●​ Reviews: Informal, Walkthrough, Technical Reviews, Inspection.
●​ Python Tools: unittest, pytest, mock, behave

2. White box testing techniques


a)​ Statement coverage
b)​ Decision Coverage
c)​ Conditional Coverage
d)​ Cylomatic complexity-Basis Path testing

White box testing involves testing the internal structures, logic, and implementation of the code.
Below are the main techniques with Python examples:

1. Statement Coverage

●​ Definition: Ensures every line of code is executed at least once.


●​ Objective: Validate that all code statements are reachable.

Example:

def check_positive(number):
if number > 0:
return "Positive"
else:
return "Not Positive"

# Test cases to ensure all lines are covered


assert check_positive(5) == "Positive" # Covers the `if` block
assert check_positive(-3) == "Not Positive" # Covers the `else`
block

Using a coverage tool like [Link], you can measure statement coverage:

pip install coverage


coverage run -m pytest test_file.py
coverage report

2. Decision Coverage

●​ Definition: Ensures all possible branches in decision points (like if or switch) are
tested.
●​ Objective: Verify that each decision (true/false) is executed.

Example:

def decide(number):
if number > 0:
return "Positive"
elif number == 0:
return "Zero"
else:
return "Negative"

# Test cases for decision coverage


assert decide(5) == "Positive" # True branch
assert decide(0) == "Zero" # Middle branch
assert decide(-3) == "Negative" # False branch

Here, every possible branch of the if-elif-else construct is covered.

3. Conditional Coverage

●​ Definition: Ensures all possible outcomes of each condition in a decision are tested.
●​ Objective: Test each condition independently to achieve full coverage.

Example:

def is_valid(number, flag):


if number > 0 and flag:
return "Valid"
else:
return "Invalid"

# Test cases for conditional coverage


assert is_valid(5, True) == "Valid" # Both conditions True
assert is_valid(5, False) == "Invalid" # Second condition False
assert is_valid(-1, True) == "Invalid" # First condition False
assert is_valid(-1, False) == "Invalid" # Both conditions False

4. Cyclomatic Complexity - Basis Path Testing

●​ Definition: Measures the complexity of the program by determining the number of


independent paths in the code.
●​ Objective: Use a control flow graph to identify all unique paths.
Formula:
Cyclomatic Complexity (CC)=E−N+2P\text{Cyclomatic Complexity (CC)} = E - N +
2PCyclomatic Complexity (CC)=E−N+2P

Where:

●​ EEE = Number of edges in the flow graph.


●​ NNN = Number of nodes.
●​ PPP = Number of connected components (typically 1 for a single program).

Example:

def process(number):
if number > 0:
if number % 2 == 0:
return "Positive Even"
else:
return "Positive Odd"
else:
return "Non-Positive"

# Basis paths for this code:


# Path 1: number > 0, number % 2 == 0
# Path 2: number > 0, number % 2 != 0
# Path 3: number <= 0

# Test cases for basis path testing


assert process(4) == "Positive Even" # Path 1
assert process(3) == "Positive Odd" # Path 2
assert process(-1) == "Non-Positive" # Path 3
To calculate Cyclomatic Complexity:

1.​ Draw the control flow graph.


2.​ Apply the formula to determine the number of independent paths.

Alternatively, use tools like radon to calculate complexity in Python:

pip install radon


radon cc -a your_file.py

Summary Table of Techniques

Technique Goal Example Tool

Statement Coverage Execute every statement at least once. [Link]

Decision Coverage Test all decision outcomes (true/false). pytest

Conditional Coverage Test all condition combinations in pytest


decisions.

Cyclomatic Identify independent paths for robust radon or manual


Complexity testing. graphing

3. Black Box testing techniques


a)​ Equivalance Partioning
b)​ Boundary Value analysis
c)​ Decision Table testing
d)​ State transition Testing
e)​ Error Guessing
f)​ Exploratory testing
Black box testing focuses on testing the functionality of an application without knowledge of its
internal code structure. The goal is to test the system based on inputs and outputs. Here are some
common black box testing techniques:

1. Equivalence Partitioning

●​ Definition: Divides input data into equivalent partitions, where each partition is expected
to produce similar outputs. Test cases are designed to cover each partition, reducing the
number of test cases without sacrificing coverage.
●​ Objective: Minimize the number of test cases while ensuring all possible input scenarios
are tested.

Example:

def categorize_age(age):
if age < 18:
return "Minor"
elif 18 <= age <= 65:
return "Adult"
else:
return "Senior"

# Equivalence partitions:
# Partition 1: age < 18 (Minor)
# Partition 2: 18 <= age <= 65 (Adult)
# Partition 3: age > 65 (Senior)

# Test cases for equivalence partitioning:


assert categorize_age(10) == "Minor" # Partition 1
assert categorize_age(30) == "Adult" # Partition 2
assert categorize_age(70) == "Senior" # Partition 3
2. Boundary Value Analysis

●​ Definition: Focuses on testing the boundaries of input ranges, as errors are often found at
the boundaries rather than the middle of input ranges.
●​ Objective: Identify potential edge cases, particularly where input data approaches the
limits.

Example:

def check_age_range(age):
if age < 18:
return "Minor"
elif 18 <= age <= 65:
return "Adult"
else:
return "Senior"

# Boundary values:
# Boundary 1: age = 17 (just before 18)
# Boundary 2: age = 18 (start of Adult range)
# Boundary 3: age = 65 (end of Adult range)
# Boundary 4: age = 66 (just after 65)

# Test cases for boundary value analysis:


assert check_age_range(17) == "Minor" # Boundary 1
assert check_age_range(18) == "Adult" # Boundary 2
assert check_age_range(65) == "Adult" # Boundary 3
assert check_age_range(66) == "Senior" # Boundary 4
3. Decision Table Testing

●​ Definition: Uses decision tables to represent combinations of inputs and corresponding


actions. This technique is useful when there are many conditions influencing the output.
●​ Objective: Cover all possible combinations of input conditions and ensure that each
combination produces the expected result.

Example:

def discount(price, is_member, is_sale):


if is_member and is_sale:
return price * 0.5 # 50% discount for members during
sale
elif is_member:
return price * 0.9 # 10% discount for members
elif is_sale:
return price * 0.8 # 20% discount during sale
else:
return price # No discount

# Decision table:
# | is_member | is_sale | Expected Discount |
# |-----------|---------|------------------|
# | True | True | 50% |
# | True | False | 10% |
# | False | True | 20% |
# | False | False | 0% |

# Test cases for decision table testing:


assert discount(100, True, True) == 50 # 50% discount
assert discount(100, True, False) == 90 # 10% discount
assert discount(100, False, True) == 80 # 20% discount
assert discount(100, False, False) == 100 # No discount

4. State Transition Testing

●​ Definition: Tests the system's behavior based on different states and transitions. This
technique is used when the system can be in one of many states and transitions between
states occur based on certain inputs.
●​ Objective: Verify that state transitions occur correctly.

Example:

class TrafficLight:
def __init__(self):
[Link] = "Red"

def change(self):
if [Link] == "Red":
[Link] = "Green"
elif [Link] == "Green":
[Link] = "Yellow"
elif [Link] == "Yellow":
[Link] = "Red"

# State transitions: Red -> Green -> Yellow -> Red

# Test cases for state transition testing:


traffic_light = TrafficLight()
# Initial state is Red
assert traffic_light.state == "Red"

# Transition from Red to Green


traffic_light.change()
assert traffic_light.state == "Green"

# Transition from Green to Yellow


traffic_light.change()
assert traffic_light.state == "Yellow"

# Transition from Yellow to Red


traffic_light.change()
assert traffic_light.state == "Red"

5. Error Guessing

●​ Definition: Involves making educated guesses about where errors might occur based on
experience or domain knowledge. Test cases are created based on these guesses.
●​ Objective: Identify potential error-prone areas in the application.

Example:

def calculate_division(a, b):


if b == 0:
raise ValueError("Cannot divide by zero")
return a / b

# Error guessing test cases:


try:
calculate_division(10, 0)
except ValueError:
pass # Expected error: Cannot divide by zero

# Test with valid inputs


assert calculate_division(10, 2) == 5

6. Exploratory Testing

●​ Definition: Involves exploring the system without predefined test cases. Testers try
different inputs and actions based on their understanding of the application and its
potential edge cases.
●​ Objective: Discover defects through unscripted testing based on tester intuition.

Example:

●​ In Python, exploratory testing is often conducted manually by interacting with the


application in a flexible and dynamic manner. For example, you might test user input in
forms or simulate interactions that haven't been explicitly described in the test plan.

Summary Table of Techniques

Technique Goal Example Use

Equivalence Partitioning Divide inputs into valid and Categorizing age groups (Minor,
invalid partitions. Adult, Senior).

Boundary Value Analysis Test boundaries of input ranges. Age ranges for minors, adults, and
seniors.

Decision Table Testing Test combinations of inputs and Discount calculation based on
corresponding outputs. membership and sales.
State Transition Testing Test system behavior across Traffic light state transitions (Red,
different states and transitions. Green, Yellow).

Error Guessing Use experience to guess potential Testing division by zero.


error-prone areas.

Exploratory Testing Test the system with an open mind Manually interacting with
and flexible approach. application features.
Module 4 - STLC
1. Test Planning

In the Software Testing Life Cycle (STLC), Test Planning is a crucial phase where a detailed
approach for testing activities is outlined. During this phase, the testing objectives, strategy,
scope, resources, schedule, and deliverables are defined. When applying this to a Python project,
test planning can be tailored to the specific testing framework (such as unittest, pytest, or
nose), tools, and methods used in the project.

Here’s a basic structure for Test Planning in Python:

1. Test Objectives

●​ Define the testing objectives: What is the primary purpose of testing? (e.g., verifying
functionality, ensuring non-regression, performance, security, etc.)

2. Test Scope

●​ Define which modules and features will be tested.


●​ Exclude any features that are out of scope (e.g., third-party integrations).

3. Test Strategy

●​ Define the types of testing to be conducted (e.g., unit tests, integration tests, system tests,
acceptance tests).
●​ Select the testing framework (unittest, pytest, nose).

4. Resources

●​ Identify the resources needed for testing: hardware, software, test environments, and
tools.
●​ Assign roles: who will be responsible for writing tests, executing tests, and reviewing
results.
5. Test Environment

●​ Define the test environment setup (e.g., database, API mockups, file systems).
●​ Ensure that dependencies (e.g., Python version, external libraries) are managed via
[Link] or a virtual environment.

6. Test Deliverables

●​ List the expected deliverables, such as test cases, test scripts, test execution reports,
defect reports, and coverage reports.

7. Test Schedule

●​ Create a timeline for executing tests.


●​ Include deadlines for test development, execution, and reporting.

8. Risk Mitigation

●​ Identify any potential risks in the project and plan for their mitigation (e.g., missing tests,
inadequate test coverage).

9. Exit Criteria

●​ Define when the testing phase can be considered complete (e.g., all critical tests passed,
sufficient test coverage achieved).

Example: Test Planning for a Python Project

# Example Test Plan using unittest in Python

import unittest
import my_module # Module to be tested

# Test Plan Overview:


# 1. Test Objectives: Ensure functionality of my_module.
# 2. Test Scope: Focus on testing all functions in my_module.
# 3. Test Strategy: Unit testing using unittest.
# 4. Resources: Testing environment with Python 3.x, unittest
framework.
# 5. Deliverables: Test cases, execution reports, bug reports.

class TestMyModule([Link]):

def test_add_function(self):
"""Test the add function of my_module"""
result = my_module.add(3, 5)
[Link](result, 8)

def test_subtract_function(self):
"""Test the subtract function of my_module"""
result = my_module.subtract(10, 3)
[Link](result, 7)

def test_multiply_function(self):
"""Test the multiply function of my_module"""
result = my_module.multiply(4, 6)
[Link](result, 24)

def test_divide_function(self):
"""Test the divide function of my_module"""
result = my_module.divide(10, 2)
[Link](result, 5)

def test_divide_by_zero(self):
"""Test divide by zero exception"""
with [Link](ZeroDivisionError):
my_module.divide(10, 0)

# Test Execution
if __name__ == "__main__":
[Link]()

# Resources: Python 3.x, unittest library, virtual environment.


# Exit Criteria: All tests pass successfully, and there are no
unresolved issues.

Key Components:

●​ Test Objectives: Verify that the functions in my_module work correctly.


●​ Test Scope: Test arithmetic functions (addition, subtraction, multiplication, division).
●​ Test Strategy: Use unittest for unit testing.
●​ Test Deliverables: Test case scripts, execution logs, and bug reports.

2. Testing Metrics

In Python testing, testing metrics are used to evaluate the effectiveness and quality of the testing
process. These metrics help identify areas that need improvement and ensure that the testing
efforts are aligned with the project’s goals. Some common testing metrics include code coverage,
test execution, defect density, and others.
Here are the key testing metrics and how you can use them in Python testing:

1. Code Coverage

●​ Definition: Code coverage measures the percentage of the codebase that is executed
during testing. It helps identify untested or under-tested code.
●​ Tools: [Link], pytest-cov, unittest

Example: Measuring code coverage with [Link]:

pip install coverage


coverage run -m unittest discover
coverage report
coverage html # Creates an HTML report

●​ Metrics:
○​ Line Coverage: Percentage of lines of code covered by tests.
○​ Branch Coverage: Percentage of code branches (if statements) covered by tests.
○​ Function Coverage: Percentage of functions covered by tests.

The result will show how well the test suite covers your code. Aim for higher coverage, but keep
in mind that 100% coverage does not guarantee bug-free code.

2. Test Execution Time

●​ Definition: The amount of time taken to run the tests. It helps in identifying slow tests
and optimizing test execution.
●​ Tools: pytest, unittest

Example using pytest:

pytest --maxfail=1 --disable-warnings --tb=short


This command shows the duration for each test and helps you analyze where optimization is
needed.

3. Test Pass Rate

●​ Definition: The percentage of tests that pass out of the total tests executed.
●​ Formula: Pass Rate=(Number of Passed TestsTotal Number of Tests)×100\text{Pass
Rate} = \left( \frac{\text{Number of Passed Tests}}{\text{Total Number of Tests}}
\right) \times 100Pass Rate=(Total Number of TestsNumber of Passed Tests​)×100
●​ Tools: pytest, unittest, nose

Example:

pytest --maxfail=3 --disable-warnings

This will help you track how many tests pass or fail and measure the overall quality of your tests.

4. Defect Density

●​ Definition: The number of defects found per unit of code, often measured per thousand
lines of code (KLOC).
●​ Formula: Defect Density=Number of DefectsKLOC\text{Defect Density} =
\frac{\text{Number of Defects}}{\text{KLOC}}Defect Density=KLOCNumber of
Defects​
●​ Tools: Bug tracking tools, e.g., JIRA, GitHub issues

This metric helps track the quality of the code and how effective your testing is in identifying
defects.

5. Test Case Effectiveness

●​ Definition: The percentage of test cases that find defects or failures. This metric helps in
evaluating whether the tests are designed to identify bugs.
●​ Formula: Test Case Effectiveness=(Number of Defects DetectedTotal Number of Test
Cases Run)×100\text{Test Case Effectiveness} = \left( \frac{\text{Number of Defects
Detected}}{\text{Total Number of Test Cases Run}} \right) \times 100Test Case
Effectiveness=(Total Number of Test Cases RunNumber of Defects Detected​)×100

If most test cases pass without detecting defects, the test suite may be inadequate.

6. Defect Discovery Rate

●​ Definition: The rate at which defects are discovered during testing. This metric is useful
to understand how quickly defects are identified during the test process.
●​ Formula: Defect Discovery Rate=Defects FoundTime Taken\text{Defect Discovery
Rate} = \frac{\text{Defects Found}}{\text{Time Taken}}Defect Discovery Rate=Time
TakenDefects Found​

Tracking the defect discovery rate helps you understand how quickly the quality of the product is
being assessed during testing.

7. Test Run Frequency

●​ Definition: This metric tracks how often tests are executed during the software
development lifecycle.
●​ Tools: CI/CD tools like Jenkins, GitLab CI, CircleCI

Frequent test runs indicate an active and thorough testing process. The tests can be run after
every code commit or in scheduled intervals.

8. Test Stability

●​ Definition: Stability of tests refers to how consistently tests pass when the codebase
remains unchanged. Unstable tests often fail randomly due to environmental issues,
timing problems, or dependencies.
●​ Tools: pytest, unittest
Monitoring test stability can help identify flaky tests that need to be addressed for a more reliable
test suite.

Example of Tracking Metrics in Python Using pytest and pytest-cov:

You can combine multiple tools like pytest and [Link] to generate detailed metrics:

pip install pytest pytest-cov

Run tests with coverage and generate reports:

pytest --cov=my_module --cov-report=html --maxfail=5


--disable-warnings

This will:

●​ Measure code coverage (--cov=my_module).


●​ Limit test failures to 5 (--maxfail=5).
●​ Disable warnings during execution (--disable-warnings).
●​ Generate an HTML report for coverage (--cov-report=html).

Conclusion:

By tracking these testing metrics, you can continuously improve your testing process and ensure
that the software is reliable, maintainable, and of high quality. These metrics can be incorporated
into your testing pipeline to gain insights into both the effectiveness of your tests and the quality
of your code.
3. Effective Test Case Writing

Effective test case writing is essential to ensure that your Python code is thoroughly tested and
that bugs or issues are detected early in the development cycle. Here are some tips and guidelines
for writing effective test cases in Python using frameworks like unittest, pytest, or nose.

1. Understand the Requirements

●​ Purpose: Before writing any test case, you should clearly understand the functionality
you are testing. Review the requirements, user stories, and code specifications to identify
the expected behavior of the system.
●​ Test Types: Decide the type of test (unit test, integration test, functional test, etc.) based
on the requirements.

2. Use a Structured Approach

Each test case should be written in a consistent and structured way. A typical test case structure
includes the following:

●​ Test Case ID: A unique identifier for the test case.


●​ Test Case Name: A brief description of the test.
●​ Test Input: The input values or conditions required for the test.
●​ Expected Output: The expected result of the test.
●​ Actual Output: The actual result obtained after running the test.
●​ Status: Whether the test passes or fails.

3. Write Tests for Small Units of Functionality

●​ Unit Testing: Each test case should test a small, isolated unit of the program (e.g., a
single function or method). This makes it easier to track down problems when a test fails.
●​ Example: Testing a simple function for adding two numbers:

# Function to be tested
def add(a, b):
return a + b

# Test case for the add function using unittest


import unittest

class TestMathOperations([Link]):
def test_add(self):
# Test case to check the add function
result = add(3, 5)
[Link](result, 8)
if __name__ == "__main__":
[Link]()

4. Test Edge Cases

●​ Edge cases are situations that might not happen often but can cause problems. These
could be:
○​ Inputs at the boundary of acceptable values.
○​ Empty inputs or null values.
○​ Large inputs, like very large numbers or large strings.
●​ Example: Edge case of adding two negative numbers:

def test_add_negative_numbers(self):
result = add(-3, -5)
[Link](result, -8)

5. Test Invalid Inputs

Always test how the code behaves with invalid inputs. This is crucial for ensuring robustness and
stability.
●​ Example: What happens if you pass strings instead of numbers:

def test_add_invalid_input(self):
with [Link](TypeError):
add("three", 5)

6. Use Descriptive Test Names

A good test name should describe the behavior or scenario being tested. It should be easy to
understand what the test is doing just by looking at the name.

●​ Example: Instead of a generic name like test_func1, use something descriptive like
test_add_function_with_valid_numbers.

7. Keep Tests Independent

●​ Each test case should be independent of others. A test should not rely on the success or
failure of other tests.
●​ Example: Don’t rely on the outcome of test_add when testing other functions. Each
test should set up its own environment.

8. Mock External Dependencies

If your code interacts with external systems like databases, APIs, or file systems, use mocking to
simulate those dependencies in your tests. This makes tests more predictable and faster.

●​ Example: Using [Link] to mock a database call:

from [Link] import patch

def get_user_from_db(user_id):
# Imagine this connects to a database to fetch a user
pass
class TestDatabase([Link]):
@patch('module_name.get_user_from_db')
def test_get_user(self, mock_get_user):
mock_get_user.return_value = {'id': 1, 'name': 'John
Doe'}
result = get_user_from_db(1)
[Link](result, {'id': 1, 'name': 'John Doe'})

9. Use Assertions Effectively

●​ Assertions are used to compare the expected and actual outputs. Common assertions
include:
○​ assertEqual(a, b): Verifies that a is equal to b.
○​ assertNotEqual(a, b): Verifies that a is not equal to b.
○​ assertTrue(a): Verifies that a is True.
○​ assertFalse(a): Verifies that a is False.
○​ assertRaises(Exception): Verifies that an exception is raised.
●​ Example:

[Link](add(1, 2), 3)
[Link](ValueError, function_that_raises_value_error)

10. Run Tests Frequently

●​ Run your tests frequently, especially when making code changes, to ensure that the
system still works as expected. Consider using Continuous Integration (CI) tools like
Jenkins, GitLab CI, or Travis CI to automate test runs.
11. Maintain Good Test Coverage

●​ Ensure that your test suite covers a wide range of scenarios, including typical use cases,
edge cases, and error cases. Tools like [Link] can help track test coverage.

Example with [Link]:

pip install coverage


coverage run -m unittest discover
coverage report

12. Test Performance (Optional)

If performance is critical, write tests that check how the application behaves under load, such as
how fast a function executes or how it handles large datasets.

13. Keep Tests Simple

●​ Write simple, clear tests that are easy to maintain. Avoid complex logic in your test
cases—tests should validate behavior, not contain logic that could be tested elsewhere.

Example:​
# Instead of testing the implementation in a complicated way,
just test the expected behavior
def test_add_simple(self):
[Link](add(1, 2), 3)

Summary of Best Practices for Writing Effective Test Cases:

●​ Understand the Requirements: Write tests based on clear requirements.


●​ Test Small Units: Write unit tests that test one small piece of functionality.
●​ Use Descriptive Names: Name tests clearly so it’s easy to understand what’s being
tested.
●​ Cover Edge Cases: Test with boundary and unusual inputs.
●​ Test Invalid Inputs: Ensure the program handles errors gracefully.
●​ Use Mocking: Mock external dependencies to make tests isolated and faster.
●​ Use Assertions: Use appropriate assertions to compare actual vs expected results.
●​ Test Coverage: Ensure that your tests cover a wide range of use cases.

By following these practices, you’ll be able to write effective, reliable, and maintainable test
cases for your Python code, improving the overall quality of your software.

4. Test Plan

Creating a Test Plan in Python involves documenting the strategy, scope, resources, and
schedule for testing a software application. The Test Plan provides a comprehensive guide to the
testing activities for a particular project and outlines the objectives, approach, and scope of
testing.

Here's an overview of how to create a test plan in Python, including its key components and
structure.

1. Test Plan Overview

A Test Plan typically contains the following sections:

1.​ Introduction
2.​ Test Objectives
3.​ Test Scope
4.​ Test Criteria
○​ Entry Criteria
○​ Exit Criteria
5.​ Testing Strategy
6.​ Testing Tools
7.​ Test Deliverables
8.​ Test Schedule
9.​ Resources and Responsibilities
10.​Risk and Contingencies
11.​Approvals

2. Example Test Plan Structure for Python Project

1. Introduction

●​ Purpose: This section outlines the purpose of the Test Plan. It should define what will be
tested and why it is important.​
Example:​
This Test Plan covers the testing activities for the Python project "User Registration
System." The objective is to ensure the application works as intended and meets the
quality standards for functionality, performance, and security.

2. Test Objectives

●​ What is being tested?: Identify the key areas of the software that need testing
(e.g., business logic, database interactions, user interface, etc.).​
Example:​
The objectives of this test plan are:
○​ Validate the correctness of user registration functionality.
○​ Ensure input validation is handled properly.
○​ Test the handling of edge cases for user input.
○​ Validate the interaction with the database for storing user data.

3. Test Scope

●​ In Scope: Define what will be tested.


●​ Out of Scope: Define what will not be tested.​
Example:​
In Scope:
○​ Registration form submission
○​ Validation of input fields (email, username, password)
○​ Database interaction (user creation and storage)
○​ Handling of successful and failed registration attempts
●​ Out of Scope:
○​ User login functionality
○​ UI/UX design and responsiveness

4. Test Criteria

●​ Entry Criteria: Conditions that must be met before testing can begin.
●​ Exit Criteria: Conditions that must be met before testing can be considered
complete.​
Example:​
Entry Criteria:
○​ Test environment setup completed (e.g., database and server setup).
○​ Test cases written and reviewed.
●​ Exit Criteria:
○​ All critical test cases have passed.
○​ No high-priority defects remain unresolved.

5. Testing Strategy

●​ Test Types: Specify the types of testing to be performed (unit tests, integration tests,
system tests, acceptance tests).
●​ Test Levels: Define the test levels (e.g., unit testing, integration testing,
system testing, regression testing).​
Example:​
Test Types:
○​ Unit Testing: Each function (e.g., email validation, password
strength checker) will be tested independently using unittest
framework.
○​ Integration Testing: Integration between the registration form and
the database will be tested.
○​ System Testing: End-to-end registration flow will be tested.
○​ Regression Testing: Ensure new changes have not broken existing
functionality.

6. Testing Tools

●​ Identify the tools you will use for writing and executing the tests.​
Example:
○​ Test Framework: unittest (Python’s built-in testing framework)
○​ Test Coverage Tool: [Link]
○​ Mocking Tool: [Link] to mock external dependencies
such as database or API calls
○​ CI/CD Tool: Jenkins or GitLab for automated test execution

7. Test Deliverables

●​ List the items that will be delivered at the end of the testing process.​
Example:
○​ Test cases document
○​ Test execution reports
○​ Defect reports
○​ Test coverage reports

8. Test Schedule

●​ Provide a timeline for testing activities. Include test execution start and end
dates, as well as deadlines for reviewing and delivering test results.​
Example:
○​ Test Case Development: January 5 - January 10
○​ Test Execution: January 11 - January 15
○​ Defect Fixing: January 16 - January 20
○​ Final Test Review: January 21

9. Resources and Responsibilities


●​ Testers: List the names or roles of people responsible for testing.
●​ Developers: Include people responsible for fixing defects identified during
testing.​
Example:
○​ Testers: John Doe (Test Lead), Jane Smith (Test Engineer)
○​ Developers: Tom Johnson (Backend Developer)

10. Risk and Contingencies

●​ Identify potential risks and the mitigation strategies.​


Example:​
Risks:
○​ Lack of availability of testing environment.
○​ Unresolved issues from earlier versions.
●​ Contingencies:
○​ Have an alternative testing environment ready.
○​ Assign additional resources to handle critical issues.

11. Approvals

●​ List the individuals or teams responsible for approving the test plan and the
test execution results.​
Example:
○​ Test Plan Approval: John Doe (Test Manager)
○​ Test Results Approval: Jane Smith (Project Manager)

3. Test Plan Example for Python Project

Here’s a sample Test Plan document for a hypothetical Python project, "User Registration
System."

# Test Plan for User Registration System


## 1. Introduction
This Test Plan covers the testing activities for the "User
Registration System" built in Python. The goal is to validate
the correctness of the registration process, input validations,
and database interactions.
## 2. Test Objectives
- Validate the correctness of user registration functionality.
- Ensure that input fields are validated correctly.
- Test the handling of invalid and edge-case inputs.
- Verify successful data storage in the database.
## 3. Test Scope
**In Scope**:
- Registration form submission.
- Field validations (email, username, password).
- Database interaction.
**Out of Scope**:
- User login functionality.
- UI/UX design and responsiveness.
## 4. Test Criteria
**Entry Criteria**:
- Test environment is set up.
- Test cases have been written and reviewed.
**Exit Criteria**:
- All high-priority test cases have passed.
- No critical defects remain unresolved.
## 5. Testing Strategy
**Test Types**:
- **Unit Testing**: Validate individual functions (e.g.,
`validate_email`).
- **Integration Testing**: Ensure that registration integrates
with the database.
- **System Testing**: Test the complete registration flow.
- **Regression Testing**: Ensure that changes do not break
existing functionality.
## 6. Testing Tools
- **Test Framework**: `unittest`
- **Mocking**: `[Link]`
- **Test Coverage**: `[Link]`
- **CI/CD**: Jenkins
## 7. Test Deliverables
- Test cases document.
- Test execution logs.
- Defect logs.
- Test coverage reports.
## 8. Test Schedule
- **Test Case Development**: January 5 - January 10
- **Test Execution**: January 11 - January 15
- **Defect Fixing**: January 16 - January 20
- **Final Test Review**: January 21
## 9. Resources and Responsibilities
- **Testers**: John Doe (Test Lead), Jane Smith (Test Engineer)
- **Developers**: Tom Johnson (Backend Developer)
## 10. Risk and Contingencies
**Risks**:
- Unavailability of test environment.
- Unresolved issues from previous versions.
**Contingencies**:
- Have backup environments ready.
- Allocate extra resources for defect fixing.
## 11. Approvals
- **Test Plan Approval**: John Doe (Test Manager)
- **Test Results Approval**: Jane Smith (Project Manager)

Conclusion

A Test Plan is a critical document that sets the foundation for all testing activities and ensures
that the testing process is organized, efficient, and aligned with the project’s objectives. By
clearly outlining the test objectives, scope, strategies, and tools, a good Test Plan helps in
achieving comprehensive test coverage and ultimately delivering a high-quality product.

5. Preparation of Test plan documentation

Creating a Test Plan Documentation for a Python project involves detailed planning for all
aspects of the testing process. The documentation provides a structured approach to testing,
outlining the goals, scope, resources, timelines, and procedures. Here's a step-by-step guide on
how to prepare Test Plan Documentation specifically for a Python-based project.

Test Plan Documentation Structure for Python

1.​ Introduction
○​ Purpose: Describe the purpose of the test plan and what the testing process will
achieve.
○​ Scope: Define what features of the project will be tested and what will not be
tested.
○​ References: Provide any references such as design documents, requirements, or
standards that the test plan follows.

Example:​
## 1. Introduction

The purpose of this Test Plan is to outline the testing


strategy, objectives, scope, and resources required for the
"User Registration System" written in Python. This plan will
ensure that the registration process functions correctly, input
data is validated, and user data is accurately stored in the
database.

### Scope
This plan covers the validation of the registration
functionality, including input validations and database
interaction. Non-functional testing, such as UI/UX design, is
out of scope for this plan.

### References
- User Registration System - Requirements Document
- Python Project Setup - [Link]

2.​ Test Objectives


○​ What will be tested: Define the key functionalities that need to be tested.
○​ Why it’s important: Describe the importance of testing each functionality or
module.

Example:​
## 2. Test Objectives
The main objectives of this testing effort are:
- Ensure that the user registration form correctly validates
email, username, and password fields.
- Validate that the system handles edge cases (empty fields,
invalid email format, etc.).
- Verify that user data is correctly inserted into the database.
- Ensure the system gracefully handles invalid inputs (e.g.,
invalid email, weak passwords).

3.​ Test Scope


○​ In Scope: Outline the specific areas that will be tested.
○​ Out of Scope: Define the areas or features that will not be tested.

Example:​
## 3. Test Scope

### In Scope
- Functional tests for registration form submission.
- Input field validation (email, password, and username).
- Interaction with the database to store user information.

### Out of Scope


- UI/UX design testing.
- Performance testing.
- User login functionality.

4.​ Test Criteria


○​ Entry Criteria: Define the conditions that must be met before testing can begin.
○​ Exit Criteria: Define the conditions that must be met for testing to be considered
complete.

Example:​
## 4. Test Criteria

### Entry Criteria


- Test environment is set up with the necessary dependencies
(e.g., database, Python environment).
- Test cases have been written and reviewed.
- All dependencies and libraries are correctly configured.

### Exit Criteria


- All high-priority test cases have passed.
- No critical defects remain open.
- Test cases executed and defect logs are reviewed.

5.​ Testing Strategy


○​ Test Types: List the types of tests that will be performed (unit tests, integration
tests, system tests, etc.).
○​ Test Levels: Define the levels of testing (unit testing, integration testing, system
testing).
○​ Test Methodologies: Describe the testing methodologies (e.g., manual testing,
automated testing with Python testing frameworks).

Example:​
## 5. Testing Strategy

### Test Types


- **Unit Testing**: Each function, such as email validation and
password strength check, will be tested individually.
- **Integration Testing**: Testing the interaction between the
user registration form and the database.
- **System Testing**: Testing the entire registration flow from
form submission to user storage.
- **Regression Testing**: Ensure that updates to the system do
not affect existing functionality.

### Test Methodologies


- Automated testing using the `unittest` framework for unit
tests.
- Mocking database interactions using `[Link]`.

6.​ Testing Tools


○​ Identify the tools and frameworks that will be used for testing.
○​ Tools for test automation, mocking, test execution, and coverage tracking.

Example:​
## 6. Testing Tools

- **Test Framework**: `unittest` (Python’s built-in testing


framework)
- **Mocking**: `[Link]` for simulating external
dependencies like the database.
- **Test Coverage**: `[Link]` for tracking test coverage.
- **Continuous Integration**: Jenkins or GitLab CI for
automating test execution during code commits.
7.​ Test Deliverables
○​ List all the deliverables expected from the testing process, including reports, test
cases, and logs.

Example:​
## 7. Test Deliverables
- Test cases document.
- Test execution logs.
- Defect reports and resolution logs.
- Test coverage reports.

8.​ Test Schedule


○​ Provide a timeline for the testing activities, from test case creation to test
execution and defect resolution.

Example:​
## 8. Test Schedule

- **Test Case Development**: January 5 - January 10


- **Test Execution**: January 11 - January 15
- **Defect Fixing**: January 16 - January 20
- **Final Test Review**: January 21

9.​ Resources and Responsibilities


○​ Identify the individuals or teams responsible for various tasks during the testing
process.

Example:​
## 9. Resources and Responsibilities

- **Testers**: John Doe (Test Lead), Jane Smith (Test Engineer)


- **Developers**: Tom Johnson (Backend Developer)

10.​Risk and Contingencies


○​ Identify potential risks during the testing phase and the strategies to mitigate those
risks.

Example:​
## 10. Risk and Contingencies

**Risks**:
- Unavailability of the test environment or dependencies.
- Unresolved issues from the previous versions affecting new
tests.

**Contingencies**:
- Backup environments will be set up to mitigate delays.
- Additional resources will be allocated to handle critical
defects.

11.​Approvals
○​ Identify the individuals or teams that must approve the Test Plan and the final test
results.

Example:​
## 11. Approvals

- **Test Plan Approval**: John Doe (Test Manager)


- **Test Results Approval**: Jane Smith (Project Manager)
Complete Test Plan Documentation Example

Here is how the final Test Plan might look in Markdown format for a Python project:

# Test Plan for User Registration System

## 1. Introduction
The purpose of this Test Plan is to outline the testing
strategy, objectives, scope, and resources required for the
"User Registration System" written in Python. This plan will
ensure that the registration process functions correctly, input
data is validated, and user data is accurately stored in the
database.

### Scope
This plan covers the validation of the registration
functionality, including input validations and database
interaction. Non-functional testing, such as UI/UX design, is
out of scope for this plan.

### References
- User Registration System - Requirements Document
- Python Project Setup - [Link]

## 2. Test Objectives
The main objectives of this testing effort are:
- Ensure that the user registration form correctly validates
email, username, and password fields.
- Validate that the system handles edge cases (empty fields,
invalid email format, etc.).
- Verify that user data is correctly inserted into the database.
- Ensure the system gracefully handles invalid inputs (e.g.,
invalid email, weak passwords).

## 3. Test Scope

### In Scope
- Functional tests for registration form submission.
- Input field validation (email, password, and username).
- Interaction with the database to store user information.

### Out of Scope


- UI/UX design testing.
- Performance testing.
- User login functionality.

## 4. Test Criteria

### Entry Criteria


- Test environment is set up with the necessary dependencies
(e.g., database, Python environment).
- Test cases have been written and reviewed.
- All dependencies and libraries are correctly configured.

### Exit Criteria


- All high-priority test cases have passed.
- No critical defects remain open.
- Test cases executed and defect logs are reviewed.

## 5. Testing Strategy

### Test Types


- **Unit Testing**: Each function, such as email validation and
password strength check, will be tested individually.
- **Integration Testing**: Testing the interaction between the
user registration form and the database.
- **System Testing**: Testing the entire registration flow from
form submission to user storage.
- **Regression Testing**: Ensure that updates to the system do
not affect existing functionality.

### Test Methodologies


- Automated testing using the `unittest` framework for unit
tests.
- Mocking database interactions using `[Link]`.

## 6. Testing Tools
- **Test Framework**: `unittest`
- **Mocking**: `[Link]`
- **Test Coverage**: `[Link]`
- **CI/CD**: Jenkins
## 7. Test Deliverables
- Test cases document.
- Test execution logs.
- Defect logs.
- Test coverage reports.

## 8. Test Schedule
- **Test Case Development**: January 5 - January 10
- **Test Execution**: January 11 - January 15
- **Defect Fixing**: January 16 - January 20
- **Final Test Review**: January 21

## 9. Resources and Responsibilities


- **Testers**: John Doe (Test Lead), Jane Smith (Test Engineer)
- **Developers**: Tom Johnson (Backend Developer)

## 10. Risk and Contingencies


- **Risks**: Unavailability of the test environment.
- **Contingencies**: Backup environments will be set up.

## 11. Approvals
- **Test Plan Approval**: John Doe
- **Test Results Approval**: Jane Smith

This documentation will provide a comprehensive plan for your Python testing efforts, ensuring
that all aspects of the project are thoroughly tested.
6. Test Development

Test Development in Python refers to the process of creating and executing test cases to
validate the functionality, performance, and reliability of your Python application. Here's a
structured approach to test development in Python:

1. Choosing the Right Testing Framework

The first step in test development is selecting the appropriate testing framework for your project.
Common frameworks for Python include:

●​ unittest: Python's built-in unit testing framework. It provides a test discovery


mechanism, assertions, and test runners.
●​ pytest: A popular testing framework that is simple and flexible, supporting both unit tests
and advanced features like fixtures and parameterized tests.
●​ nose2: Another unit testing framework, an improved version of unittest.
●​ doctest: A framework that allows you to write tests within your documentation.

For most projects, pytest is a popular choice because of its simplicity and advanced features.

2. Writing Test Cases

Test cases are written to ensure the different parts of your application function as expected. Each
test case should check one unit of functionality, such as a function or method.

Test Case Structure (Using unittest)

1.​ Test Class: Inherit from [Link].


2.​ Test Methods: Each method represents a single test case, and the method name should
begin with test_.
3.​ Assertions: Use assertions to verify the correctness of your application’s behavior.

Example:

import unittest
# Example function to test
def add(a, b):
return a + b
class TestMathOperations([Link]):
def test_add_positive_numbers(self):
result = add(1, 2)
[Link](result, 3)
def test_add_negative_numbers(self):
result = add(-1, -1)
[Link](result, -2)
def test_add_mixed_numbers(self):
result = add(-1, 2)
[Link](result, 1)
if __name__ == '__main__':
[Link]()

In this example, three tests are written for the add function:

●​ Positive numbers: add(1, 2)


●​ Negative numbers: add(-1, -1)
●​ Mixed numbers: add(-1, 2)

Test Case Structure (Using pytest)

For pytest, the structure is simpler and more flexible:

# Example function to test


def add(a, b):
return a + b
# Test cases for pytest
def test_add_positive_numbers():
assert add(1, 2) == 3

def test_add_negative_numbers():
assert add(-1, -1) == -2

def test_add_mixed_numbers():
assert add(-1, 2) == 1

pytest automatically detects the test functions by looking for functions that start with test_
and can handle assertions without needing assertEqual like in unittest.

3. Running Tests
For unittest, you can run tests using the command:​
python -m unittest discover
For pytest, you can run tests using the command:​
pytest

Both frameworks will automatically detect all test cases in your project and run them.

4. Using Mocking in Tests

Mocking is essential when testing code that depends on external systems or APIs (such as
databases or web services). Python provides several ways to mock external dependencies.

●​ [Link]: The [Link] module helps simulate external dependencies.

Example:

import unittest
from [Link] import patch

def get_user_data(user_id):
# Simulating a call to an external API
response = external_api_call(user_id)
return response

class TestExternalApi([Link]):

@patch('module_name.external_api_call')
def test_get_user_data(self, mock_external_api):
# Mocking the external API call response
mock_external_api.return_value = {'user_id': 1, 'name':
'John Doe'}

result = get_user_data(1)

[Link](result, {'user_id': 1, 'name': 'John


Doe'})
mock_external_api.assert_called_once_with(1)

if __name__ == '__main__':
[Link]()

In this example, external_api_call is mocked to avoid making real API calls during
testing.
5. Test Coverage

Test coverage measures how much of the code is covered by tests. Python tools like [Link]
can be used to analyze your test coverage.

Running [Link]:
Install the tool:​
pip install coverage
Run tests with coverage:​
coverage run -m unittest discover
Report coverage:​
coverage report
View coverage details in HTML:​
coverage html

6. Parameterized Tests

Sometimes, you want to run the same test with multiple inputs. This is where parameterized tests
come in handy. In pytest, you can use @[Link] to pass different
inputs to a test function.

Example:

import pytest
@[Link]("a, b, expected", [(1, 2, 3), (-1, -1,
-2), (-1, 2, 1)])
def test_add(a, b, expected):
assert add(a, b) == expected

This approach allows testing the add function with multiple sets of inputs and expected results.
7. Test Automation and CI/CD

Once the tests are developed, automating them ensures they are run frequently to catch any
issues early. Integrate your tests into a CI/CD pipeline using tools like GitHub Actions,
Jenkins, or GitLab CI.

●​ GitHub Actions: You can configure workflows in the .github/workflows directory


to run your tests automatically on each push or pull request.
●​ Jenkins: Set up a Jenkins pipeline to automatically run the tests as part of the build
process.

8. Best Practices for Test Development in Python

●​ Write small, focused tests: Each test should verify only one thing.
●​ Name tests clearly: Test method names should describe the behavior being tested.
●​ Use setup/teardown methods: setUp() and tearDown() in unittest to prepare
and clean up the test environment.
●​ Avoid writing tests for trivial code: Focus on testing the complex, critical parts of your
application.
●​ Use assertions effectively: Ensure the assertions are meaningful and reflect the expected
behavior.

Conclusion

Test development in Python is an essential part of maintaining a reliable and maintainable


codebase. By using frameworks like unittest or pytest, you can write clear, effective tests
that ensure your code behaves as expected. Mocking, parameterized tests, and coverage tools
help enhance the quality of your tests, while integrating tests into CI/CD pipelines ensures they
are executed frequently and consistently.
7. Test Scenario

A test scenario in Python refers to a high-level description of a specific situation or condition


that needs to be tested to ensure that the software behaves as expected. It outlines the
preconditions, steps, expected outcomes, and sometimes the postconditions for a specific test
case. Test scenarios are often written at a broader level than individual test cases and are part of a
comprehensive testing strategy.

Components of a Test Scenario

1.​ Test Scenario ID: A unique identifier for the scenario.


2.​ Test Scenario Description: A brief description of the functionality being tested.
3.​ Preconditions: Any conditions that must be met before the test is executed (e.g., user
logged in, database initialized).
4.​ Test Steps: The sequence of actions to perform during the test.
5.​ Expected Result: The expected outcome of the test based on the test steps.
6.​ Postconditions: The state of the system after the test execution (if applicable).

Example Test Scenario for a Python Application

Suppose you're testing a Python function that adds two numbers:

def add(a, b):


return a + b

Test Scenario 1: Test the Addition of Two Positive Numbers

●​ Test Scenario ID: TS001


●​ Test Scenario Description: Test the add() function with two positive integers.
●​ Preconditions: The Python environment is set up and the add() function is defined and
available for testing.
●​ Test Steps:
1.​ Call the add() function with the parameters 2 and 3.
2.​ Observe the result of the function.
●​ Expected Result: The result should be 5 because 2 + 3 equals 5.
●​ Postconditions: No changes are expected in the system state after the test.

Test Scenario 2: Test the Addition of Two Negative Numbers

●​ Test Scenario ID: TS002


●​ Test Scenario Description: Test the add() function with two negative integers.
●​ Preconditions: The Python environment is set up and the add() function is defined and
available for testing.
●​ Test Steps:
1.​ Call the add() function with the parameters -2 and -3.
2.​ Observe the result of the function.
●​ Expected Result: The result should be -5 because -2 + (-3) equals -5.
●​ Postconditions: No changes are expected in the system state after the test.

Test Scenario 3: Test the Addition of a Positive and a Negative Number

●​ Test Scenario ID: TS003


●​ Test Scenario Description: Test the add() function with one positive and one negative
integer.
●​ Preconditions: The Python environment is set up and the add() function is defined and
available for testing.
●​ Test Steps:
1.​ Call the add() function with the parameters 2 and -3.
2.​ Observe the result of the function.
●​ Expected Result: The result should be -1 because 2 + (-3) equals -1.
●​ Postconditions: No changes are expected in the system state after the test.
Test Scenario Development for Python Projects

Steps to Develop Test Scenarios in Python:

1.​ Identify the Functionality to Test:


○​ Understand the core functionality of the Python code that needs testing (e.g.,
function, method, or feature).
2.​ Analyze Requirements or User Stories:
○​ Review project requirements or user stories to determine what features need to be
tested.
3.​ Write High-Level Scenarios:
○​ Develop test scenarios at a high level, focusing on testing broad functionality
rather than fine-grained details.
4.​ Determine Preconditions, Steps, and Expected Results:
○​ List the necessary conditions to test each functionality and the specific steps to be
followed.
5.​ Include Postconditions (If Necessary):
○​ Define the state of the application after the test, especially for tests that may
change the state of the system.
6.​ Group Related Scenarios:
○​ Group similar scenarios together (e.g., testing all forms of user login) to ensure
coverage of all critical workflows.

Test Scenario Example in a Web Application (Using Flask)

Suppose you have a simple Flask application that provides an API for adding two numbers:

from flask import Flask, jsonify, request

app = Flask(__name__)

@[Link]('/add', methods=['GET'])
def add_numbers():
a = int([Link]('a'))
b = int([Link]('b'))
return jsonify({'result': a + b})

if __name__ == '__main__':
[Link](debug=True)

Test Scenario 1: Test the Addition API with Positive Numbers

●​ Test Scenario ID: TS001


●​ Test Scenario Description: Test the /add endpoint with two positive integers.
●​ Preconditions: The Flask app is running, and the /add endpoint is available.
●​ Test Steps:
1.​ Send a GET request to /add?a=3&b=5.
2.​ Observe the response.
●​ Expected Result: The response should be a JSON object with {"result": 8}.
●​ Postconditions: No changes are expected in the system state after the test.

Test Scenario 2: Test the Addition API with a Positive and Negative Number

●​ Test Scenario ID: TS002


●​ Test Scenario Description: Test the /add endpoint with a positive and a negative
integer.
●​ Preconditions: The Flask app is running, and the /add endpoint is available.
●​ Test Steps:
1.​ Send a GET request to /add?a=5&b=-3.
2.​ Observe the response.
●​ Expected Result: The response should be a JSON object with {"result": 2}.
●​ Postconditions: No changes are expected in the system state after the test.
Benefits of Test Scenarios:

1.​ Clear Structure: Test scenarios provide a clear structure for testing and ensure that all
parts of an application are covered.
2.​ Reusability: Scenarios can be reused across different tests, especially when testing
similar functionality.
3.​ Risk Mitigation: By defining scenarios, you ensure that potential edge cases and
negative scenarios are covered.
4.​ Improved Collaboration: Test scenarios help in better communication among testers,
developers, and stakeholders since they clearly define what will be tested.

Conclusion

Test scenarios are an important tool in the software testing process, as they help outline the
expected behavior of features in a broader sense. By breaking down each functionality into
scenarios, you can ensure comprehensive test coverage and validate your application’s behavior
under different conditions. Test scenarios also help maintain clarity and consistency across
testing efforts, especially for large or complex applications.

8. Test Case Design

Test Case Design in Python refers to the process of creating individual test cases to verify that a
specific piece of functionality in your Python code behaves as expected. It is part of a structured
testing process to ensure that the code is reliable, bug-free, and meets the specified requirements.

Key Steps in Test Case Design

1.​ Understand the Requirements:


○​ Study the requirements or user stories to understand the functionality of the
feature being tested.
2.​ Identify the Testable Components:
○​ Break down the functionality into smaller components, such as functions,
methods, or classes, that can be tested.
3.​ Define Test Case Scenarios:
○​ Consider different scenarios for each component, including typical cases, edge
cases, and negative cases.
4.​ Determine the Expected Result:
○​ For each test case, clearly define the expected result based on the specification of
the functionality.
5.​ Prepare Test Data:
○​ Determine the data that will be used for testing, including valid, invalid, and
boundary values.
6.​ Automate the Test Case:
○​ Write automated tests using a testing framework like unittest, pytest, or
others.

Example: Test Case Design for a Simple Python Function

Let's say you have the following Python function, which adds two numbers:

def add(a, b):


return a + b

Test Case Design Steps:

1. Test Case for Adding Two Positive Numbers

●​ Test Case ID: TC001


●​ Test Case Description: Test adding two positive numbers.
●​ Preconditions: The add() function is implemented and ready to be tested.
●​ Test Input:
1.​ a = 3
2.​ b = 5
●​ Test Steps:
1.​ Call add(3, 5).
2.​ Observe the result.
●​ Expected Result: The result should be 8 because 3 + 5 = 8.
●​ Postconditions: No changes to system state.
●​ Status: Pass/Fail (Based on the result of the actual test).

Test Case Implementation (Using unittest):

import unittest

class TestMathOperations([Link]):

def test_add_two_positive_numbers(self):
result = add(3, 5)
[Link](result, 8)

if __name__ == '__main__':
[Link]()

2. Test Case for Adding Two Negative Numbers

●​ Test Case ID: TC002


●​ Test Case Description: Test adding two negative numbers.
●​ Preconditions: The add() function is implemented and ready to be tested.
●​ Test Input:
1.​ a = -2
2.​ b = -3
●​ Test Steps:
1.​ Call add(-2, -3).
2.​ Observe the result.
●​ Expected Result: The result should be -5 because -2 + -3 = -5.
●​ Postconditions: No changes to system state.
●​ Status: Pass/Fail.

Test Case Implementation (Using unittest):

class TestMathOperations([Link]):

def test_add_two_negative_numbers(self):
result = add(-2, -3)
[Link](result, -5)

if __name__ == '__main__':
[Link]()

3. Test Case for Adding a Positive and a Negative Number

●​ Test Case ID: TC003


●​ Test Case Description: Test adding a positive number and a negative number.
●​ Preconditions: The add() function is implemented and ready to be tested.
●​ Test Input:
1.​ a = 5
2.​ b = -3
●​ Test Steps:
1.​ Call add(5, -3).
2.​ Observe the result.
●​ Expected Result: The result should be 2 because 5 + -3 = 2.
●​ Postconditions: No changes to system state.
●​ Status: Pass/Fail.

Test Case Implementation (Using unittest):


class TestMathOperations([Link]):

def test_add_positive_and_negative(self):
result = add(5, -3)
[Link](result, 2)

if __name__ == '__main__':
[Link]()

4. Test Case for Adding Zero

●​ Test Case ID: TC004


●​ Test Case Description: Test adding zero to a number.
●​ Preconditions: The add() function is implemented and ready to be tested.
●​ Test Input:
1.​ a = 0
2.​ b = 5
●​ Test Steps:
1.​ Call add(0, 5).
2.​ Observe the result.
●​ Expected Result: The result should be 5 because 0 + 5 = 5.
●​ Postconditions: No changes to system state.
●​ Status: Pass/Fail.

Test Case Implementation (Using unittest):

class TestMathOperations([Link]):

def test_add_zero(self):
result = add(0, 5)
[Link](result, 5)

if __name__ == '__main__':
[Link]()

5. Test Case for Non-integer Input (Negative Case)

●​ Test Case ID: TC005


●​ Test Case Description: Test adding non-integer inputs (e.g., strings).
●​ Preconditions: The add() function is implemented and ready to be tested.
●​ Test Input:
1.​ a = "a"
2.​ b = 5
●​ Test Steps:
1.​ Call add("a", 5).
2.​ Observe the result.
●​ Expected Result: The function should raise a TypeError because string and integer
cannot be added.
●​ Postconditions: No changes to system state.
●​ Status: Pass/Fail.

Test Case Implementation (Using unittest):

class TestMathOperations([Link]):

def test_add_non_integer_input(self):
with [Link](TypeError):
add("a", 5)

if __name__ == '__main__':
[Link]()
Test Case Design Best Practices

1.​ Cover Different Input Types: Test with a variety of valid and invalid inputs to ensure
robust error handling.
2.​ Test Boundary Conditions: Test edge cases, such as adding very large or very small
numbers, or zero values.
3.​ Be Specific and Focused: Each test case should test only one specific behavior or edge
case.
4.​ Use Descriptive Test Case Names: The test case ID and description should clearly
indicate the test's purpose.
5.​ Maintain Consistency: Ensure that test cases follow a consistent structure for easier
maintenance and readability.
6.​ Automate Test Execution: Use a test framework like unittest, pytest, or others to
automate test execution and reporting.
7.​ Ensure Isolated Tests: Each test case should be independent, with no reliance on other
tests.

Conclusion

Test case design is a critical process to ensure the quality and reliability of your Python code. By
creating well-structured, focused test cases, you can verify that your application behaves as
expected across a variety of input scenarios, including edge cases and error conditions.
Automated testing frameworks like unittest and pytest make it easier to implement and
execute test cases, contributing to better code quality and faster development cycles.

9. Levels of testing

In Python, as in other software development environments, levels of testing refer to the different
stages or granularities at which software is tested. These levels help ensure that various aspects
of the system are verified independently and as part of the overall solution. The levels of testing
generally include:
1. Unit Testing

●​ Purpose: Test individual units or components of the code (e.g., functions or methods).
●​ Scope: Focuses on a single function or method.
●​ Objective: Ensure that each small piece of the application works as intended.
●​ Tools in Python:
○​ unittest
○​ pytest
○​ nose

Example of Unit Testing in Python:

For a function add(a, b):

def add(a, b):


return a + b

A unit test might look like:

import unittest

class TestMathOperations([Link]):

def test_add(self):
[Link](add(3, 4), 7)

if __name__ == '__main__':
[Link]()

2. Integration Testing
●​ Purpose: Test the interaction between multiple units or components to ensure they work
together.
●​ Scope: Involves integrating components, such as checking if a function interacts correctly
with external systems or databases.
●​ Objective: Identify issues related to the integration of different components.
●​ Tools in Python:
○​ pytest (can be used for integration testing by configuring fixtures)
○​ unittest (can also be used for integration testing when test suites involve
multiple modules)

Example of Integration Testing in Python:

If you have a function that integrates with an external API, you can mock the API call and test
how it integrates with the rest of your system.

import unittest
from [Link] import patch

class TestAPIIntegration([Link]):

@patch('[Link]')
def test_api_integration(self, mock_get):
# Mock the API response
mock_get.return_value.json.return_value = {'data':
'value'}

# Call the function that uses [Link]


response = fetch_data_from_api()

[Link](response, {'data': 'value'})


if __name__ == '__main__':
[Link]()

3. System Testing

●​ Purpose: Test the complete system as a whole, ensuring that all components work
together as expected.
●​ Scope: The entire application is tested in an environment similar to production.
●​ Objective: Ensure the software meets the requirements and behaves as expected in a full
deployment scenario.
●​ Tools in Python:
○​ pytest
○​ unittest
○​ Selenium (for testing web applications)
○​ Pytest-Django (for Django applications)

Example of System Testing in Python:

You might simulate user interaction in a web app using Selenium to verify that the app behaves
as expected in a real-world scenario.

from selenium import webdriver

def test_login():
driver = [Link]()
[Link]("[Link]

username_input = driver.find_element_by_id("username")
password_input = driver.find_element_by_id("password")
username_input.send_keys("user")
password_input.send_keys("password")

login_button = driver.find_element_by_id("login_button")
login_button.click()

assert "Welcome" in driver.page_source


[Link]()

4. Acceptance Testing

●​ Purpose: Validate that the software satisfies the business requirements and is ready for
release.
●​ Scope: Focuses on ensuring the system meets user needs and specifications.
●​ Objective: Ensure the application is ready for deployment from a user's perspective,
confirming that all requirements are met.
●​ Tools in Python:
○​ pytest (especially with fixtures)
○​ Behave (a BDD framework for Python)

Example of Acceptance Testing in Python:

Acceptance tests are often written in a BDD (Behavior Driven Development) style, where test
scenarios are written in plain language.

from behave import given, when, then

@given('I am on the login page')


def step_given_on_login_page(context):
[Link]('[Link]
@when('I enter a valid username and password')
def step_when_enter_credentials(context):

[Link].find_element_by_id('username').send_keys('user')

[Link].find_element_by_id('password').send_keys('passwo
rd')

@then('I should see the welcome message')


def step_then_see_welcome(context):
assert 'Welcome' in [Link].page_source

5. Regression Testing

●​ Purpose: Ensure that new changes, such as bug fixes or feature additions, have not
introduced new issues or broken existing functionality.
●​ Scope: Focuses on verifying that previously working features still function as expected.
●​ Objective: Prevent regression issues where new changes negatively affect existing
features.
●​ Tools in Python:
○​ pytest
○​ unittest
○​ Selenium (for web-based regression testing)

Example of Regression Testing in Python:

Running previously defined unit tests after adding a new feature to ensure no functionality is
broken.

$ pytest test_math_operations.py
6. Performance Testing

●​ Purpose: Evaluate the application's performance, scalability, and responsiveness under


load.
●​ Scope: Tests how the system performs under various conditions, such as high traffic or
large datasets.
●​ Objective: Ensure the system can handle the expected user load and meet performance
benchmarks.
●​ Tools in Python:
○​ Locust (for load testing)
○​ Pytest-benchmark (for performance testing)

Example of Performance Testing in Python using pytest-benchmark:

def test_function_performance(benchmark):
result = benchmark(add, 3, 5)
assert result == 8

7. Smoke Testing

●​ Purpose: Verify that the most critical functionalities of the system work as expected.
●​ Scope: A subset of tests, usually covering the main features.
●​ Objective: Perform an initial check to ensure the system is stable enough for more
detailed testing.
●​ Tools in Python:
○​ pytest
○​ unittest

Example of Smoke Testing in Python:

Testing the core functionality, such as ensuring the main page of a web application loads
successfully.

def test_homepage():
response = [Link]('/')
assert response.status_code == 200

8. Alpha and Beta Testing

●​ Purpose: Alpha testing is performed by the development team, and beta testing is done
by a small group of real users outside the development team.
●​ Scope: Both tests focus on identifying bugs before the software is released to a larger
audience.
●​ Objective: Get real-world feedback and identify issues that were missed during previous
testing levels.
●​ Tools in Python:
○​ Beta and alpha testing might not directly involve tools but are more about
feedback and manual testing.

Conclusion

The different levels of testing in Python help ensure comprehensive verification and validation of
software. Each level focuses on different aspects of the system, from individual components (unit
testing) to the entire system's behavior in a production-like environment (system testing). Using
the appropriate tools and techniques at each level allows you to build high-quality, reliable
Python applications.

10. Testing types

In Python, testing types refer to the different approaches used to verify and validate the behavior
of the software during its development. Each testing type focuses on different aspects of the
application to ensure its quality, performance, and correctness. Here are the key testing types in
Python:
1. Unit Testing

●​ Purpose: Verify the functionality of individual units (e.g., functions, methods, classes) of
the code in isolation.
●​ Scope: Tests a small, isolated piece of functionality, such as a single function or method.
●​ Tools:
○​ unittest
○​ pytest
○​ nose

Example: Testing a simple function that adds two numbers.​


def add(a, b):
return a + b​
import unittest

class TestMathOperations([Link]):

def test_add(self):
[Link](add(3, 4), 7)

if __name__ == '__main__':
[Link]()

2. Integration Testing

●​ Purpose: Test the interaction between different modules, services, or components of the
system to ensure they work together as expected.
●​ Scope: Focuses on the flow of data and control between components/modules.
●​ Tools:
○​ pytest
○​ unittest
○​ requests (for testing APIs)
○​ Mocking libraries like [Link]

Example: Testing a function that fetches data from an external API and processes it.​
import unittest
from [Link] import patch

class TestAPIIntegration([Link]):

@patch('[Link]')
def test_integration_with_api(self, mock_get):
mock_get.return_value.json.return_value = {'data':
'value'}
result = fetch_data_from_api()
[Link](result, {'data': 'value'})

if __name__ == '__main__':
[Link]()

3. System Testing

●​ Purpose: Test the complete system in a production-like environment to ensure the entire
application functions correctly as a whole.
●​ Scope: Includes the entire system, including integrated components and external services.
●​ Tools:
○​ pytest
○​ unittest
○​ Selenium (for web applications)
○​ Appium (for mobile applications)

Example: Testing a web application's login page by simulating user interaction with the browser
using Selenium.​
from selenium import webdriver

def test_login():
driver = [Link]()
[Link]("[Link]
driver.find_element_by_id("username").send_keys("user")
driver.find_element_by_id("password").send_keys("password")
driver.find_element_by_id("login_button").click()
assert "Welcome" in driver.page_source
[Link]()

4. Acceptance Testing

●​ Purpose: Ensure the application meets the business requirements and is ready for release.
Acceptance tests are often written from the perspective of the end user.
●​ Scope: Verifies that the system fulfills user stories or specific business requirements.
●​ Tools:
○​ Behave (for Behavior-Driven Development - BDD)
○​ pytest

Example: Writing scenarios in natural language (e.g., using Gherkin syntax) to define the
expected behavior of a feature.​
Feature: Login functionality

Scenario: User logs in successfully


Given I am on the login page
When I enter valid credentials
Then I should be redirected to the dashboard
Implementation using Behave:​
from behave import given, when, then

@given('I am on the login page')


def step_given_on_login_page(context):
[Link]('[Link]

@when('I enter valid credentials')


def step_when_enter_credentials(context):

[Link].find_element_by_id('username').send_keys('user')

[Link].find_element_by_id('password').send_keys('passwo
rd')

@then('I should be redirected to the dashboard')


def step_then_redirected_to_dashboard(context):
assert 'Dashboard' in [Link].page_source

5. Regression Testing

●​ Purpose: Ensure that new changes (bug fixes, enhancements) have not negatively
impacted existing features.
●​ Scope: Tests all critical functionality to confirm it is still working after updates.
●​ Tools:
○​ pytest
○​ unittest
○​ Selenium (for web apps)

Example: Running previously written tests after a code change to ensure existing features are
unaffected.​
$ pytest

6. Performance Testing

●​ Purpose: Test the application's performance, scalability, and responsiveness under load.
●​ Scope: Evaluate how the system performs under different conditions, including high
traffic and large data volumes.
●​ Tools:
○​ Locust (load testing)
○​ Pytest-benchmark

Example: Using pytest-benchmark to test the execution time of a function.​


def test_performance(benchmark):
result = benchmark(add, 3, 5)
assert result == 8

7. Smoke Testing

●​ Purpose: Conduct a preliminary check to verify that the most critical features of the
application are working.
●​ Scope: A quick, basic check to ensure the build is stable enough for more detailed
testing.
●​ Tools:
○​ unittest
○​ pytest

Example: Verifying that a web application's homepage loads correctly.​


def test_homepage():
response = [Link]('/')
assert response.status_code == 200

8. Stress Testing

●​ Purpose: Test the application's ability to handle extreme conditions, such as an unusually
high load or unexpected inputs.
●​ Scope: Ensure the system can handle stressful or unexpected conditions gracefully.
●​ Tools:
○​ Locust
○​ Apache JMeter (for more complex scenarios)
●​ Example: Testing how the system performs under a sudden, large spike in traffic.

9. Usability Testing

●​ Purpose: Evaluate how user-friendly and intuitive the application is for its end users.
●​ Scope: Focuses on user experience and interface design.
●​ Tools:
○​ Selenium (to automate UI testing)
○​ PyAutoGUI (for automating GUI-based interactions)
●​ Example: Testing the ease with which a user can navigate a form and submit data.

10. Security Testing

●​ Purpose: Identify and address vulnerabilities, ensuring the application is secure and
resistant to attacks.
●​ Scope: Tests against common security threats like SQL injection, cross-site scripting
(XSS), and more.
●​ Tools:
○​ OWASP ZAP (for web security testing)
○​ Bandit (Python security testing tool)
Example: Testing for SQL injection vulnerabilities by sending specially crafted requests.​
import requests
response =
[Link]('[Link]
234')

11. Alpha and Beta Testing

●​ Purpose: Alpha testing is done by the development team, while beta testing is performed
by a limited set of end users outside the development team.
●​ Scope: Gather feedback and identify defects that were missed in earlier testing phases.
●​ Tools: Not necessarily testing tools, but user feedback and bug reporting tools.
●​ Example: Releasing a beta version of an app to a select group of users for feedback.

Conclusion

Each testing type plays a crucial role in verifying the behavior, functionality, and quality of your
application. By using the appropriate testing types for different stages of development, you can
ensure that your Python application is robust, secure, and ready for production. You can use tools
like unittest, pytest, Selenium, Behave, and others to implement these testing types
efficiently.

11. Requirement traceability matrix

A Requirement Traceability Matrix (RTM) is a document used to ensure that all requirements
of a project are being tested and verified. It links requirements to test cases and helps in tracking
the coverage of requirements throughout the testing process.

In Python, you can implement an RTM by maintaining a mapping between the requirements and
their associated test cases. Below is a general approach for creating an RTM in Python, which
can be customized to your project.
1. Define the Requirements and Test Cases

The RTM typically includes the following columns:

●​ Requirement ID: Unique identifier for each requirement.


●​ Requirement Description: A brief description of the requirement.
●​ Test Case ID: The ID of the test case that verifies the requirement.
●​ Test Case Description: A description of the test case.
●​ Status: The current status (e.g., Passed, Failed, Not Executed).

You can structure the data using Python dictionaries or data structures like lists and pandas
DataFrames to maintain and track the mapping between requirements and test cases.

2. Using Python to Create and Track RTM

Below is an example implementation in Python using a simple dictionary-based approach:

# RTM Structure
rtm = [
{"Requirement ID": "REQ-001", "Requirement Description":
"User must be able to log in", "Test Case ID": "TC-001", "Test
Case Description": "Test login functionality", "Status":
"Passed"},
{"Requirement ID": "REQ-002", "Requirement Description":
"System should send an email on registration", "Test Case ID":
"TC-002", "Test Case Description": "Test email sending after
registration", "Status": "Failed"},
{"Requirement ID": "REQ-003", "Requirement Description":
"User profile should be editable", "Test Case ID": "TC-003",
"Test Case Description": "Test profile editing", "Status": "Not
Executed"},
{"Requirement ID": "REQ-004", "Requirement Description":
"System must handle 1000 concurrent users", "Test Case ID":
"TC-004", "Test Case Description": "Test load capacity of the
system", "Status": "Passed"},
]

# Function to print RTM


def print_rtm(rtm):
print(f"{'Requirement ID':<15} {'Requirement
Description':<40} {'Test Case ID':<15} {'Test Case
Description':<40} {'Status':<15}")
print("-" * 120)
for entry in rtm:
print(f"{entry['Requirement ID']:<15}
{entry['Requirement Description']:<40} {entry['Test Case
ID']:<15} {entry['Test Case Description']:<40}
{entry['Status']:<15}")

# Example usage
print_rtm(rtm)

# Function to update status of a test case


def update_test_status(requirement_id, status):
for entry in rtm:
if entry['Requirement ID'] == requirement_id:
entry['Status'] = status
print(f"Status of requirement {requirement_id}
updated to {status}")
return
print(f"Requirement {requirement_id} not found.")

# Update test status example


update_test_status("REQ-002", "Passed")
print_rtm(rtm)

3. Explanation of the Code

●​ RTM Data Structure: The RTM is represented as a list of dictionaries where each
dictionary holds the details of one requirement and its associated test case(s).
●​ print_rtm Function: This function is used to print the RTM in a tabular format.
●​ update_test_status Function: This function allows you to update the test case
status for a particular requirement. It takes the Requirement ID and the new status as
input.

4. Output Example

When running the above code, the output will look like this:

Requirement ID Requirement Description Test Case ID


Test Case Description Status
----------------------------------------------------------------
----------------------------------------
REQ-001 User must be able to log in TC-001
Test login functionality Passed
REQ-002 System should send an email on registration
TC-002 Test email sending after registration Failed
REQ-003 User profile should be editable TC-003
Test profile editing Not Executed
REQ-004 System must handle 1000 concurrent users TC-004
Test load capacity of the system Passed
Status of requirement REQ-002 updated to Passed
Requirement ID Requirement Description Test Case ID
Test Case Description Status
----------------------------------------------------------------
----------------------------------------
REQ-001 User must be able to log in TC-001
Test login functionality Passed
REQ-002 System should send an email on registration
TC-002 Test email sending after registration Passed
REQ-003 User profile should be editable TC-003
Test profile editing Not Executed
REQ-004 System must handle 1000 concurrent users TC-004
Test load capacity of the system Passed

5. Using Pandas for a More Complex RTM

If the requirements and test cases are large, or if you want to perform more advanced operations
like filtering or exporting the RTM to CSV, using pandas can be very effective.

import pandas as pd

# Define RTM as a dictionary


data = {
"Requirement ID": ["REQ-001", "REQ-002", "REQ-003",
"REQ-004"],
"Requirement Description": ["User must be able to log in",
"System should send an email on registration", "User profile
should be editable", "System must handle 1000 concurrent
users"],
"Test Case ID": ["TC-001", "TC-002", "TC-003", "TC-004"],
"Test Case Description": ["Test login functionality", "Test
email sending after registration", "Test profile editing", "Test
load capacity of the system"],
"Status": ["Passed", "Failed", "Not Executed", "Passed"]
}

# Create a DataFrame
df = [Link](data)

# Print the RTM


print(df)

# Update the status of a test case


def update_test_status_pandas(requirement_id, status):
[Link][df['Requirement ID'] == requirement_id, 'Status'] =
status
print(f"Status of requirement {requirement_id} updated to
{status}")

# Example of updating status


update_test_status_pandas("REQ-002", "Passed")
print(df)
6. Benefits of Using an RTM in Python

●​ Traceability: Ensures that every requirement has a corresponding test case.


●​ Easy to Update: As the project progresses, you can easily update the status of test cases.
●​ Reports and Documentation: You can generate RTM reports in various formats, such as
CSV or Excel, using tools like pandas.
●​ Improves Test Coverage: Ensures that all requirements are tested, reducing the risk of
missing any functionality.

Conclusion

Using a Requirement Traceability Matrix (RTM) in Python helps maintain the integrity of the
project requirements and ensures that all functional and non-functional requirements are tested
appropriately. Python tools like unittest, pytest, and pandas make it easy to build,
update, and maintain an RTM, enhancing the efficiency of the testing process.

12. Test Closure

Test Closure refers to the final phase of the software testing lifecycle where testing activities are
concluded, and results are documented. It involves closing the testing process by ensuring that all
necessary activities are completed and the testing objectives are met. In Python, you can
automate parts of the test closure process, such as generating test reports, ensuring that all test
cases have been executed, and summarizing the testing activities.

Here are the key steps involved in Test Closure in Python:

1. Finalizing Test Execution

Make sure that all planned test cases have been executed, and the test results are documented.
This involves:

●​ Ensuring that all tests have passed or failed appropriately.


●​ Tracking tests that were not executed due to blockers or other issues.
●​ Verifying that there are no open issues or defects that remain unresolved.

2. Generating Test Reports

Test reports summarize the results of the testing phase, highlighting:

●​ Which test cases passed or failed.


●​ Test coverage and traceability.
●​ Defects found during testing.
●​ Recommendations for improvements or next steps.

In Python, you can use tools like unittest, pytest, or nose to generate these reports.

Example with pytest:

You can generate a test report in a variety of formats, such as HTML, JUnit, or JSON.

Step 1: Run Tests and Generate Report

$ pytest --maxfail=1 --disable-warnings -q --html=[Link]

Step 2: Using Python to Open and Review the Report

Once the tests are complete, you can open the HTML report using Python (if necessary):

import webbrowser

# Open the generated HTML report


[Link]('[Link]')

3. Test Case Review and Closure

At the end of the test phase, review the following:


●​ Test Coverage: Ensure all requirements have been tested by checking the Requirement
Traceability Matrix (RTM).
●​ Defects Management: All defects should be recorded and prioritized. Ensure that defects
are either fixed or deferred for future releases.
●​ Test Execution Summary: Document how many test cases passed, failed, or were
blocked, and summarize the reasons for any failures.

Example of a Summary Report in Python:

def generate_test_summary(test_results):
passed = len([result for result in test_results if
result['status'] == 'Passed'])
failed = len([result for result in test_results if
result['status'] == 'Failed'])
not_executed = len([result for result in test_results if
result['status'] == 'Not Executed'])

summary = {
"Total Test Cases": len(test_results),
"Passed": passed,
"Failed": failed,
"Not Executed": not_executed,
"Pass Percentage": (passed / len(test_results)) * 100 if
test_results else 0
}

return summary

# Example Test Data


test_results = [
{"Test Case ID": "TC-001", "Status": "Passed"},
{"Test Case ID": "TC-002", "Status": "Failed"},
{"Test Case ID": "TC-003", "Status": "Passed"},
{"Test Case ID": "TC-004", "Status": "Not Executed"}
]

# Generate summary
summary = generate_test_summary(test_results)
print("Test Closure Summary:")
print(f"Total Test Cases: {summary['Total Test Cases']}")
print(f"Passed: {summary['Passed']}")
print(f"Failed: {summary['Failed']}")
print(f"Not Executed: {summary['Not Executed']}")
print(f"Pass Percentage: {summary['Pass Percentage']}%")

4. Test Deliverables

At the end of the testing phase, deliverables should include:

●​ Test Results Report: A detailed report of test case execution.


●​ Defect Report: A report listing all defects found during testing, including their severity
and status (open, resolved, deferred).
●​ Test Logs: Logs of test execution, which can be helpful for debugging.
●​ Test Closure Report: A final summary document stating the completion of testing,
including any issues, risks, or known limitations.

Example: Test Closure Report Generation

def generate_test_closure_report(test_results):
passed = len([result for result in test_results if
result['status'] == 'Passed'])
failed = len([result for result in test_results if
result['status'] == 'Failed'])
not_executed = len([result for result in test_results if
result['status'] == 'Not Executed'])

report = f"""
Test Closure Report
--------------------
Total Test Cases: {len(test_results)}
Passed: {passed}
Failed: {failed}
Not Executed: {not_executed}

Final Conclusion:
Test execution completed. {passed} test(s) passed, {failed}
test(s) failed, and {not_executed} test(s) were not executed.
"""

return report

# Example Test Results


test_results = [
{"Test Case ID": "TC-001", "Status": "Passed"},
{"Test Case ID": "TC-002", "Status": "Failed"},
{"Test Case ID": "TC-003", "Status": "Passed"},
{"Test Case ID": "TC-004", "Status": "Not Executed"}
]

# Generate Test Closure Report


closure_report = generate_test_closure_report(test_results)
print(closure_report)

5. Post-Test Analysis

After the tests are completed and the closure report is generated, the testing team can:

●​ Analyze Test Results: Evaluate which areas need improvement or have caused defects.
●​ Learn from the Failures: Identify common causes for failure and suggest improvements
to avoid future issues.
●​ Verify Unresolved Issues: Make sure unresolved defects are documented and tracked for
future releases.

Conclusion

Test Closure in Python involves the completion of test execution, generation of test reports,
summarizing results, documenting defects, and delivering the final reports. Using tools like
pytest for test execution and pandas or simple Python functions for result processing and
report generation, you can automate and manage the test closure process efficiently.

4o mini
Module 5 - Test Case Execution
1. Test Environment

To execute test cases in a test environment using Python, you typically follow these steps:

1. Set Up Your Test Environment

●​ Install Dependencies: Ensure all required libraries are installed in the test environment.
●​ Configure the Environment: Set up configurations (e.g., environment variables,
database connections, or test-specific settings).
●​ Choose a Test Framework: Popular options include unittest, pytest, and nose2.

pip install pytest

2. Write Test Cases

●​ Define your test cases using a test framework.


●​ Use assertions to validate the expected behavior.

Example using pytest:

import pytest

def add(a, b):


return a + b

def test_add_positive_numbers():
assert add(3, 5) == 8

def test_add_negative_numbers():
assert add(-3, -5) == -8
3. Run Tests

●​ Execute tests using the command-line interface of the framework.

Example for pytest:

pytest test_file.py

Example for unittest:

python -m unittest test_file.py

4. Analyze Results

●​ Review the output to ensure all tests pass.


●​ Fix any failing test cases by debugging the code or updating the tests.

Example output for pytest:

======================== test session starts


========================
collected 2 items

test_file.py .. [100%]

========================= 2 passed in 0.02s


=========================

5. Automate Test Execution

●​ Use tools like tox or CI/CD pipelines to run tests in a dedicated test environment.

6. Advanced Testing
●​ Mocking: Use libraries like [Link] to simulate external dependencies.

Coverage: Use pytest-cov to measure code coverage.​


pip install pytest-cov

●​ pytest --cov=your_module test_file.py

2. Test Execution

When executing test cases in Python, the results are typically categorized as Passed, Failed, or
Blocked. Managing these outcomes and handling test case dependencies can be streamlined with
test frameworks and custom logic.

1. Test Case Status

●​ Passed: The test case completes successfully, and the actual outcome matches the
expected outcome.
●​ Failed: The test case completes, but the actual outcome does not match the expected
outcome.
●​ Blocked: The test case cannot be executed due to unmet dependencies (e.g., missing data,
environment setup issues, or failed prerequisite tests).

2. Implementing Test Case Execution and Dependencies

Using pytest

●​ Leverage pytest markers to manage dependencies.


●​ Use [Link] or [Link] to handle blocked test cases.

Example Code:

import pytest
# Mock function under test
def multiply(a, b):
if a is None or b is None:
raise ValueError("Inputs cannot be None")
return a * b

# Test cases
@[Link]()
def test_setup_environment():
# Simulating environment setup
assert True # Simulate successful setup

@[Link](depends=["test_setup_environment"])
def test_multiply_valid_inputs():
assert multiply(2, 3) == 6

@[Link](depends=["test_setup_environment"])
def test_multiply_invalid_inputs():
with [Link](ValueError):
multiply(None, 3)

@[Link](depends=["test_setup_environment"])
def test_multiply_blocked():
[Link]("Dependency unmet, skipping test")

Run Command:

pytest test_file.py
3. Handling Dependencies
Use the pytest-dependency plugin for managing dependent test cases.​
pip install pytest-dependency

●​ Example:
○​ test_multiply_valid_inputs and
test_multiply_invalid_inputs depend on
test_setup_environment.
○​ If test_setup_environment fails, the dependent tests are marked as
Blocked.

4. Test Execution Report

Frameworks like pytest provide clear output for Passed/Failed/Blocked cases:

======================== test session starts


========================
collected 3 items

test_file.py .s. [100%]

==================== 1 passed, 1 skipped in 0.01s


====================

5. Enhancing Reporting

Use plugins like pytest-html for generating detailed reports.​


pip install pytest-html
pytest --html=[Link]

6. Automating Dependency Validation


For complex test suites with extensive dependencies:

a)​ Maintain a dependency matrix.

b)​ Use fixtures in pytest to set up shared resources for dependent tests.

Example:​
@[Link](scope="module")
def setup_environment():
return "Environment Ready"

def test_uses_environment(setup_environment):

c)​ assert setup_environment == "Environment Ready"

Module 6 - Defect Management


1. Defect Tracking
a)​ Severity
b)​ Priority
c)​ Defect Life cycle

Here’s an outline for implementing a Defect Management System in Python, focusing on


Defect Tracking, Severity, Priority, and the Defect Life Cycle:

1. Defect Tracking

Defect tracking involves maintaining a record of all the defects identified during a project. These
defects can be logged, updated, and closed as they progress through their life cycle.

Python Implementation

from datetime import datetime


# Define Defect Status Constants
STATUS_NEW = "New"
STATUS_OPEN = "Open"
STATUS_FIXED = "Fixed"
STATUS_CLOSED = "Closed"
STATUS_REOPENED = "Reopened"

# Define Defect Severity Levels


SEVERITY_LOW = "Low"
SEVERITY_MEDIUM = "Medium"
SEVERITY_HIGH = "High"
SEVERITY_CRITICAL = "Critical"

# Define Priority Levels


PRIORITY_LOW = "Low"
PRIORITY_MEDIUM = "Medium"
PRIORITY_HIGH = "High"

# Defect Class
class Defect:
def __init__(self, defect_id, title, description, severity,
priority):
self.defect_id = defect_id
[Link] = title
[Link] = description
[Link] = severity
[Link] = priority
[Link] = STATUS_NEW
self.created_at = [Link]()
self.updated_at = self.created_at

def update_status(self, new_status):


if new_status in [STATUS_NEW, STATUS_OPEN, STATUS_FIXED,
STATUS_CLOSED, STATUS_REOPENED]:
[Link] = new_status
self.updated_at = [Link]()
else:
print("Invalid status.")

def display(self):
print(f"Defect ID: {self.defect_id}")
print(f"Title: {[Link]}")
print(f"Description: {[Link]}")
print(f"Severity: {[Link]}")
print(f"Priority: {[Link]}")
print(f"Status: {[Link]}")
print(f"Created At: {self.created_at}")
print(f"Updated At: {self.updated_at}")
print("-" * 40)

# Defect Manager Class


class DefectManager:
def __init__(self):
[Link] = {}
def add_defect(self, defect):
[Link][defect.defect_id] = defect

def update_defect_status(self, defect_id, new_status):


if defect_id in [Link]:
[Link][defect_id].update_status(new_status)
else:
print("Defect not found.")

def display_all_defects(self):
for defect in [Link]():
[Link]()

# Example Usage
if __name__ == "__main__":
# Initialize Defect Manager
manager = DefectManager()

# Create Defects
defect1 = Defect(1, "Login Issue", "User unable to login",
SEVERITY_HIGH, PRIORITY_HIGH)
defect2 = Defect(2, "UI Bug", "Button alignment issue",
SEVERITY_LOW, PRIORITY_LOW)

# Add Defects
manager.add_defect(defect1)
manager.add_defect(defect2)

# Display Defects
manager.display_all_defects()

# Update Status
manager.update_defect_status(1, STATUS_OPEN)

# Display Updated Defects


manager.display_all_defects()

2. Severity

Severity defines the impact of the defect on the system:

●​ Low: Minimal impact on the system functionality.


●​ Medium: Some impact, but system functionality is not completely broken.
●​ High: Major functionality is affected.
●​ Critical: System is unusable or critical functionalities are broken.

3. Priority

Priority indicates the urgency of addressing the defect:

●​ Low: Can be deferred.


●​ Medium: Needs to be addressed in the current development cycle.
●​ High: Requires immediate attention.

4. Defect Life Cycle

The defect life cycle typically follows these stages:

●​ New: Defect is newly reported.


●​ Open: Defect is acknowledged and under investigation.
●​ Fixed: Defect has been resolved by developers.
●​ Closed: Defect is verified and marked as resolved.
●​ Reopened: Defect is found again after being marked as resolved.

This implementation supports the creation, tracking, and updating of defects, ensuring a
structured approach to defect management.
Module 7 - Testing Tools
1. Testing Tools in Jira and BUG Zilla

To integrate testing tools in Jira and Bugzilla with Python, follow these steps. This involves
understanding their APIs, setting up Python environments, and writing scripts to interact with
these platforms for managing and automating bug tracking and test management.

1. Understand Jira and Bugzilla APIs

●​ Both Jira and Bugzilla provide REST APIs for programmatic interaction.
●​ Documentation:
○​ Jira REST API
○​ Bugzilla REST API

2. Set Up Python Environment

●​ Install Python (if not already installed).

Create a virtual environment to isolate your project dependencies:​


python -m venv jira_bugzilla_env
source jira_bugzilla_env/bin/activate # On Windows:
jira_bugzilla_env\Scripts\activate

3. Install Required Libraries

Use pip to install libraries for API interaction:​


pip install requests jira

4. Jira Integration Steps

4.1 Authenticate to Jira

●​ Jira typically uses API tokens for authentication.


●​ Steps:
1.​ Generate an API token from your Jira account.
2.​ Install and configure the jira Python library.

4.2 Example Script for Jira

from jira import JIRA

# Jira credentials
jira_server = '[Link]
api_token = 'your-api-token'
email = 'your-email@[Link]'

# Connect to Jira
jira = JIRA(server=jira_server, basic_auth=(email, api_token))

# Create a new issue


new_issue = jira.create_issue(project='TEST', summary='Bug in
feature X',
description='Steps to
reproduce...', issuetype={'name': 'Bug'})
print(f"Issue created: {new_issue.key}")

# Fetch issues from a project


issues = jira.search_issues('project=TEST')
for issue in issues:
print(f"{[Link]}: {[Link]}")

5. Bugzilla Integration Steps


5.1 Authenticate to Bugzilla

●​ Bugzilla uses API keys for authentication.


●​ Steps:
1.​ Generate an API key from your Bugzilla profile.
2.​ Use the requests library to interact with the Bugzilla REST API.

5.2 Example Script for Bugzilla

import requests

# Bugzilla credentials
bugzilla_url = '[Link]
api_key = 'your-api-key'

# Create a new bug


new_bug = {
'product': 'TestProduct',
'component': 'TestComponent',
'summary': 'Bug in feature Y',
'version': 'unspecified',
'description': 'Steps to reproduce...'
}
response = [Link](f"{bugzilla_url}/bug", json=new_bug,
params={'api_key': api_key})
if response.status_code == 200:
print(f"Bug created: {[Link]()['id']}")
else:
print(f"Error: {response.status_code} - {[Link]()}")
# Fetch bugs from Bugzilla
response = [Link](f"{bugzilla_url}/bug",
params={'api_key': api_key, 'product': 'TestProduct'})
if response.status_code == 200:
bugs = [Link]()['bugs']
for bug in bugs:
print(f"Bug ID: {bug['id']}, Summary: {bug['summary']}")
else:
print(f"Error: {response.status_code} - {[Link]()}")

6. Testing the Integration

●​ Run the scripts to ensure they work with your Jira and Bugzilla accounts.
●​ Verify that the issues/bugs created appear in their respective dashboards.

7. Automating Tests

●​ Integrate these scripts with your testing frameworks (e.g., unittest, pytest).

Example:​
import unittest

class TestJiraIntegration([Link]):
def test_create_issue(self):
# Add code to test issue creation
pass

if __name__ == "__main__":
[Link]()

8. Best Practices

●​ Use environment variables to store sensitive credentials.


●​ Add logging for debugging and tracking API interactions.
●​ Handle API errors gracefully (e.g., retries, timeouts).

2. Hands on - Test Case Writing

Writing test cases in Jira and Bugzilla involves defining a set of inputs, execution conditions, and
expected results to validate that a feature or functionality works as intended. Here’s how you can
create and manage test cases in these platforms.

Jira: Writing Test Cases

Jira doesn’t natively support test case management, but you can use:

●​ Custom Issue Types: Configure Jira to use a "Test Case" issue type.
●​ Test Management Plugins: Tools like Zephyr for Jira or Xray enhance test case
capabilities.

Steps to Write Test Cases in Jira

1.​ Log In and Access Your Project


○​ Open Jira and navigate to your project.
2.​ Create a New Issue
○​ Click on the “Create” button.
○​ Select the issue type as "Test Case" (if configured).
3.​ Fill in the Test Case Details Use the following fields for a basic test case:
○​ Summary: A brief description of the test case (e.g., "Verify login functionality
with valid credentials").
○​ Description: Detailed steps, including:
■​ Preconditions: Conditions that need to be met before execution.
■​ Steps to Reproduce: Detailed test steps.
■​ Expected Results: The anticipated result of the test.
○​ Priority: Importance of the test case.
○​ Attachments: Add screenshots or related files if needed.
4.​ Save the Test Case
○​ Click “Create” or “Save.”

Example: Test Case in Jira

Field Example Value

Summary Verify login functionality with valid credentials

Preconditions User is registered and has an active account

Steps to 1. Navigate to the login page


Reproduce 2. Enter valid credentials
3. Click on the login button

Expected Result User should be redirected to the dashboard after logging in


successfully.

Attachments Add screenshots for clarity

Bugzilla: Writing Test Cases

Bugzilla is primarily a bug-tracking tool and doesn't have dedicated support for test cases.
However, you can manage test cases as bugs or custom fields.

Steps to Write Test Cases in Bugzilla

1.​ Log In to Bugzilla


○​ Navigate to your Bugzilla instance and log in.
2.​ Create a New Bug
○​ Click on "File a Bug."
○​ Select the Product and Component relevant to the test case.
3.​ Fill in the Test Case Details
○​ Use fields in the bug form to describe the test case:
■​ Summary: A concise name for the test case (e.g., "Test Login
Functionality").
■​ Description: Include:
■​ Preconditions: Prerequisites for the test.
■​ Steps: Detailed steps to execute the test case.
■​ Expected Results: The outcome if the test case passes.
○​ Severity: Assign a low severity since this is a test case and not a bug.
○​ Attachments: Add files/screenshots if required.
4.​ Save the Test Case
○​ Submit the bug to save it as a test case.

Example: Test Case in Bugzilla

Field Example Value

Summary Test Login Functionality

Product Web Application

Component Login Page

Version 1.0

Description Preconditions: User is registered and account is active.


Steps: 1. Go to login page.
2. Enter valid credentials.
3. Click login.
Expected Result: User is redirected to the dashboard.

Severity Trivial

Attachments Screenshot of the login page

Best Practices for Writing Test Cases


1.​ Be Clear and Concise: Use simple language to describe steps and expected results.
2.​ Include Preconditions: State conditions that must be met before executing the test.
3.​ Use Attachments: Add screenshots or mockups to improve understanding.
4.​ Categorize Test Cases: Organize by priority or feature to streamline testing.
5.​ Review and Update Regularly: Keep test cases current with application updates.

3. Hands on - Test Plan Creation

Creating a Test Plan in Jira and Bugzilla involves outlining the testing strategy, scope,
objectives, resources, schedule, and deliverables for a specific project or feature. Since these
tools are primarily designed for issue/bug tracking, they require some customization or plugins to
manage test plans effectively.

Test Plan Creation in Jira

Jira doesn’t have a dedicated module for test plans, but you can:

1.​ Use the "Test Plan" Issue Type (if configured).


2.​ Install plugins like Zephyr or Xray for enhanced test management.

Steps to Create a Test Plan in Jira

1.​ Set Up the Test Plan Structure


○​ If using a plugin:
■​ Zephyr: Use the "Test Plan" option under the "Tests" menu.
■​ Xray: Use the "Test Plan" issue type.
○​ Without a plugin:
■​ Create a custom issue type named "Test Plan."
2.​ Create a Test Plan
○​ Navigate to your Jira project and click Create.
○​ Select Test Plan (or the custom issue type you've configured).
3.​ Fill in the Test Plan Details
○​ Summary: A concise name for the test plan (e.g., "Test Plan for Login Module").
○​ Description: Detailed objectives, scope, and key features to be tested.
○​ Components: Specify which components of the application are included.
○​ Assignees: Assign the test plan to a tester or QA team.
○​ Priority: Define the priority of the test plan.
○​ Test Cases (Linked Issues): Link relevant test cases (if using plugins).
4.​ Save the Test Plan
○​ Click Create to save the test plan.

Example: Test Plan in Jira

Field Example Value

Summary Test Plan for Login Module

Description Objective: Ensure the Login functionality is bug-free.


Scope: Test valid/invalid credentials, UI elements, and security aspects.
Features to Test: Login page, forgot password flow, user lockout.
Out of Scope: Database-level testing.

Components Login Page

Assignee QA Team Lead

Priority High

Linked Issues TEST-1 (Login Test Case), TEST-2 (Forgot Password Test Case)

Test Plan Creation in Bugzilla

Bugzilla does not natively support test plan creation, but you can:

1.​ Use Bug Reports to represent test plans.


2.​ Create a Custom Component for test plans.
3.​ Use third-party integrations or plugins like Testopia.

Steps to Create a Test Plan in Bugzilla

1.​ Set Up Test Plan as a Bug


○​ Log in to Bugzilla and click on File a Bug.
○​ Choose the Product and Component for your test plan (e.g., "Test Plan
Component").
2.​ Fill in the Test Plan Details
○​ Summary: Provide a concise title for the test plan.
○​ Description: Include the following sections:
■​ Objective: Purpose of the test plan.
■​ Scope: Features covered in testing.
■​ Schedule: Timeline for the testing phases.
■​ Team: Assign testers or QA team.
■​ Linked Bugs: Reference existing bugs for visibility.
○​ Attachments: Upload documents or spreadsheets detailing test cases.
3.​ Save the Test Plan
○​ Submit the bug, which represents your test plan.

Example: Test Plan in Bugzilla

Field Example Value

Summary Test Plan for Login Module

Component Test Plans

Description Objective: Validate the Login functionality.


Scope: Test login with valid and invalid credentials, security features, and UI
responsiveness.
Schedule: Start Date - Jan 15, End Date - Jan 20.
Team: QA Team Lead, Testers.
Dependencies: Bugs #12345, #67890 (for resolved issues).

Severity Trivial

Attachments Upload detailed test plan document or list of test cases.

Best Practices for Test Plan Creation

1.​ Keep it Detailed but Focused:


○​ Include clear objectives, scope, and deliverables.
2.​ Link Related Items:
○​ Associate test cases or bugs with the test plan for traceability.
3.​ Review and Update Regularly:
○​ Update the test plan as features or requirements change.
4.​ Use Attachments:
○​ Upload detailed documents for larger test plans.
5.​ Collaborate:
○​ Share the test plan with stakeholders for feedback.

Test Plan Example Document

If you’re maintaining a separate document for a test plan, it might look like this:

Section Details

Test Plan Name Test Plan for Login Module

Objective Ensure the Login Module functions as intended.

Scope Validate login functionality, forgot password flow, and lockout


scenarios.

Schedule Start Date: Jan 15, End Date: Jan 20.

Team Test Lead: Alice; Testers: Bob, Charlie.

Risks and Dependencies on resolved bugs, stable build required.


Assumptions

Test Cases Login_TC_01, Login_TC_02, etc.

4. Hands on -
a)​ Equivalence Partitioning
b)​ Boundary Value Analysis
c)​ State Transition Diagram
d)​ Decision Table

To implement Equivalence Partitioning, Boundary Value Analysis, State Transition


Diagram, and Decision Table Testing in Jira and Bugzilla using Python, you’ll need to:

1.​ Define the Test Design Techniques in a structured manner.


2.​ Leverage Jira and Bugzilla for documenting and managing these test cases.
3.​ Automate the creation and execution of these tests using Python and integrate the results
into Jira or Bugzilla.

1. Equivalence Partitioning (EP) in Jira and Bugzilla

Equivalence Partitioning involves dividing input data into partitions (valid and invalid) where
all values in a partition are expected to behave similarly.

Steps:

1.​ Identify equivalence partitions (valid and invalid inputs).


2.​ Document test cases for each partition in Jira or Bugzilla.
3.​ Automate validation of these test cases using Python.

Python Implementation Example for EP

def test_login(input_value):
valid_partition = ['user1', 'user2', 'user3'] # Example
valid users
if input_value in valid_partition:
return "Login Successful"
else:
return "Invalid User"

# Test Equivalence Partitions


test_cases = ['user1', 'invalid_user', 'user2']
for case in test_cases:
print(f"Input: {case}, Result: {test_login(case)}")

Jira/Bugzilla Integration:

●​ Jira: Use a test case template to log each partition as a separate test case and link them to
a user story.
●​ Bugzilla: File bugs for failed cases, marking them as valid or invalid partitions.

2. Boundary Value Analysis (BVA)

Boundary Value Analysis focuses on testing the edges of input ranges (e.g., minimum,
maximum, just inside/outside boundaries).

Steps:

1.​ Identify boundaries of the input domain.


2.​ Document test cases for:
○​ Lower boundary
○​ Upper boundary
○​ Just below/above the boundaries
3.​ Automate boundary validation using Python.

Python Implementation Example for BVA

def validate_age(age):
if 18 <= age <= 65:
return "Valid Age"
else:
return "Invalid Age"
# Test Boundary Values
boundary_values = [17, 18, 19, 64, 65, 66]
for age in boundary_values:
print(f"Input: {age}, Result: {validate_age(age)}")

Jira/Bugzilla Integration:

●​ Jira: Create boundary-specific test cases (e.g., "Test Age = 18").


●​ Bugzilla: Log bugs for values failing at boundaries and attach Python logs for reference.

3. State Transition Diagram (STD)

State Transition Testing validates different states of a system and the transitions between them.

Steps:

1.​ Define the states and possible transitions.


2.​ Document test cases for each transition.
3.​ Automate transition testing using Python.

Python Implementation Example for STD

# Define transitions
state_transitions = {
'Logged Out': {'login': 'Logged In'},
'Logged In': {'logout': 'Logged Out', 'timeout': 'Session
Expired'},
'Session Expired': {'login': 'Logged In'}
}

def test_transition(current_state, action):


if action in state_transitions[current_state]:
return state_transitions[current_state][action]
return "Invalid Transition"

# Test State Transitions


transitions = [
('Logged Out', 'login'),
('Logged In', 'logout'),
('Logged In', 'timeout'),
('Session Expired', 'login')
]
for state, action in transitions:
print(f"From: {state}, Action: {action}, To:
{test_transition(state, action)}")

Jira/Bugzilla Integration:

●​ Jira: Document test cases for each state and transition.


●​ Bugzilla: Log bugs for invalid transitions (e.g., "Logged In → timeout failed").

4. Decision Table Testing

Decision Table Testing evaluates combinations of inputs and the corresponding system outputs.

Steps:

1.​ Create a decision table with:


○​ Conditions (inputs)
○​ Actions (outputs)
2.​ Document test cases for all valid combinations.
3.​ Automate decision table testing using Python.
Python Implementation Example for Decision Table

# Decision table rules


decision_table = [
{'Age': 18, 'Income': 'High', 'Result': 'Eligible'},
{'Age': 17, 'Income': 'Low', 'Result': 'Not Eligible'},
{'Age': 65, 'Income': 'High', 'Result': 'Eligible'},
{'Age': 66, 'Income': 'Low', 'Result': 'Not Eligible'}
]

def check_eligibility(age, income):


for rule in decision_table:
if rule['Age'] == age and rule['Income'] == income:
return rule['Result']
return "Unknown Rule"

# Test Decision Table


test_cases = [(18, 'High'), (17, 'Low'), (65, 'High'), (66,
'Low')]
for age, income in test_cases:
print(f"Age: {age}, Income: {income}, Result:
{check_eligibility(age, income)}")

Jira/Bugzilla Integration:

●​ Jira: Use custom issue types for each rule and link cases to a decision table document.
●​ Bugzilla: Log failed cases with detailed input-output mappings.

Workflow for Jira/Bugzilla Integration Using Python


1.​ Document the Test Cases:
○​ Use Jira or Bugzilla to organize EP, BVA, STD, and Decision Table test cases.
○​ Link cases to requirements or features.
2.​ Automate Test Case Execution:
○​ Use Python to execute tests for each technique.
○​ Capture results and generate reports.
3.​ Report Issues:
○​ Use Python scripts to log issues in Jira/Bugzilla via their APIs.

Example: Log Results to Jira Using Python

from jira import JIRA

# Jira credentials
jira_server = '[Link]
email = 'your-email@[Link]'
api_token = 'your-api-token'

# Connect to Jira
jira = JIRA(server=jira_server, basic_auth=(email, api_token))

# Log issue
test_result = "Boundary Test Failed for Age=66"
new_issue = jira.create_issue(project='TEST', summary='Boundary
Value Failure',
description=test_result,
issuetype={'name': 'Bug'})
print(f"Issue logged in Jira: {new_issue.key}")

Example: Log Results to Bugzilla Using Python


import requests

# Bugzilla credentials
bugzilla_url = '[Link]
api_key = 'your-api-key'

# Log bug
bug_data = {
'product': 'WebApp',
'component': 'Login',
'summary': 'Boundary Test Failed for Age=66',
'version': '1.0',
'description': 'Age=66 failed during boundary testing.',
'severity': 'normal'
}
response = [Link](f"{bugzilla_url}/bug", json=bug_data,
params={'api_key': api_key})
print(f"Bug logged in Bugzilla: {[Link]().get('id')}")

Best Practices

1.​ Automate the creation and execution of tests using Python.


2.​ Integrate results seamlessly into Jira or Bugzilla via APIs.
3.​ Regularly review and update test cases based on product updates.

[Link]

Module 8 - Introduction to Performance Testing


1. Introduction to Performance Testing
a)​ What is performance testing?
b)​ What do you test?
c)​ What do you test?
d)​ Load ~ Stress testing
e)​ Performance Testing tool introduction

Introduction to Performance Testing with Python

Performance testing is a type of software testing that focuses on assessing how well a system
performs under certain conditions, such as varying workloads, user traffic, or resource
constraints. It helps ensure that the system performs optimally and meets expected performance
standards.

What is Performance Testing?

Performance testing involves evaluating the responsiveness, scalability, stability, and speed of a
system, application, or software under load. It helps to identify potential bottlenecks and areas of
improvement by simulating different real-world scenarios. The goal is to ensure that the software
can handle a large number of users, data, and transactions without degrading performance.

What Do You Test in Performance Testing?

Performance testing typically involves testing the following:

1.​ Response Time: How quickly the system responds to requests under varying loads.
2.​ Throughput: The number of requests the system can handle within a given time frame.
3.​ Scalability: The system's ability to scale up or down based on increasing or decreasing
load.
4.​ Stability: How well the system maintains its performance over extended periods of time
or under sustained usage.
5.​ Resource Usage: The system’s usage of CPU, memory, disk, and network resources
during load.
6.​ Error Rates: The number of errors or failures that occur as load increases.
7.​ Concurrency: The ability of the system to handle multiple users or processes
simultaneously.

Load Testing vs. Stress Testing

●​ Load Testing: Involves testing the system under a specified expected load, such as the
expected number of concurrent users or transactions. The goal is to verify that the system
can handle the expected load without significant performance degradation.
●​ Stress Testing: This is performed to determine the system's behavior under extreme or
beyond normal load. It helps to identify the breaking point or failure threshold of the
system, showing how the system behaves when pushed to its limits.

Performance Testing Tools Introduction

There are various performance testing tools available, including both open-source and
commercial solutions. Below are a few popular ones:

1.​ Apache JMeter: A widely used open-source tool for performance testing web
applications. It can simulate heavy traffic, measure response times, and analyze
performance metrics.
2.​ Locust: A Python-based load testing tool that allows you to define user behavior in
Python code, making it highly customizable and flexible.
3.​ Gatling: A powerful open-source tool designed for load testing of web applications and
services. It provides detailed reports and integrates with continuous integration systems.
4.​ Artillery: Another popular open-source tool for load testing web applications, APIs, and
microservices. It allows you to define scenarios in YAML format and is well-suited for
modern cloud-native applications.
5.​ BlazeMeter: A commercial performance testing platform built on JMeter. It allows for
the execution of large-scale performance tests with real-time monitoring and analytics.

Using Python for Performance Testing (Example with Locust)


Locust is a Python-based load testing tool that is simple to use and provides extensive flexibility
for writing test scenarios. Here’s an example of how you can use Python to test the performance
of a web service:

from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
wait_time = between(1, 5)

@task
def load_main_page(self):
[Link]("/")

@task
def load_about_page(self):
[Link]("/about")

@task
def load_contact_page(self):
[Link]("/contact")

if __name__ == "__main__":
import os
[Link]("locust")

●​ HttpUser: Represents a user interacting with the application via HTTP.


●​ task: A decorated method that represents a user behavior (e.g., loading a webpage).
●​ wait_time: Defines how long the user will wait between tasks.
Running the Test

1.​ Save the script to a file, e.g., [Link].


2.​ Run Locust from the command line by navigating to the folder where your script is and
executing locust.
3.​ Access the Locust web interface (by default, at [Link] to start
the test and define the number of users and the hatch rate (how fast users should start).

Locust provides real-time feedback on test performance, showing response times, failure rates,
and requests per second.

In summary, performance testing is a crucial part of ensuring your system works efficiently
under real-world conditions. By using tools like Locust, you can test and fine-tune your
application to meet performance standards and user expectations.
Module 9 - Introduction to Security Testing
1. Introduction to Security Testing
a)​ What is security testing
b)​ Why it is important
c)​ Types of security testing

Introduction to Security Testing with Python

Security testing is a type of software testing that ensures that an application or system is
protected against potential threats, vulnerabilities, and attacks. It involves checking the system’s
defenses and its ability to safeguard data, resources, and users against malicious activities.

What is Security Testing?

Security testing is the process of assessing the security features of a software system to identify
any vulnerabilities, weaknesses, and threats. This testing evaluates whether the system has
appropriate safeguards in place to protect data, prevent unauthorized access, and ensure the
integrity of operations.

The primary goal of security testing is to uncover vulnerabilities that could be exploited by
attackers, ensuring the system is resilient against cyber threats such as hacking, malware, data
breaches, and other malicious activities.

Why is Security Testing Important?

Security testing is essential for several reasons:

1.​ Protecting Sensitive Data: Security breaches can lead to unauthorized access to sensitive
information such as personal, financial, and business data, which could have severe
consequences, including financial loss, reputation damage, and legal penalties.
2.​ Ensuring Compliance: Many industries require compliance with regulations such as
GDPR, HIPAA, and PCI-DSS, which mandate the implementation of specific security
measures to protect data.
3.​ Preventing Attacks: Security testing helps identify and fix vulnerabilities before they are
exploited by attackers, preventing potential cyberattacks like SQL injection, cross-site
scripting (XSS), or cross-site request forgery (CSRF).
4.​ Maintaining Business Continuity: Ensuring security can protect the business from
downtime, loss of intellectual property, and damage to customer trust.
5.​ Improving System Resilience: By identifying weaknesses, security testing ensures that
the system is robust and can withstand attempts to compromise it.

Types of Security Testing

There are several types of security testing, each focusing on different aspects of system security:

1.​ Vulnerability Scanning:


○​ Involves using automated tools to scan an application for known vulnerabilities. It
detects weak spots, outdated components, or misconfigurations that may be
exploited.
○​ Example tools: OpenVAS, Nessus, and Nexpose.
2.​ Penetration Testing (Pen Testing):
○​ A simulated attack on the system to identify vulnerabilities that could be exploited
by a real attacker. Pen testing may involve network, web application, or social
engineering attacks.
○​ Example tools: Metasploit, Burp Suite, and OWASP ZAP.
3.​ Security Audits:
○​ A comprehensive review of the system's security policies, protocols, and
configurations to ensure compliance with security standards and best practices.
○​ Manual testing or automated tools may be used to audit code, architecture, and
infrastructure.
4.​ Risk Assessment:
○​ Involves identifying and assessing the potential risks to the application, including
the likelihood of security threats and their potential impact on the system.
5.​ Static Application Security Testing (SAST):
○​ Analyzing the source code or binaries of the application to identify vulnerabilities
such as buffer overflows, SQL injection, and others that could arise from the
code.
○​ Example tools: SonarQube, Checkmarx, and Fortify.
6.​ Dynamic Application Security Testing (DAST):
○​ Testing an application in its running state (dynamic testing), usually through
penetration tests or scanning for runtime vulnerabilities, such as those that occur
during web application execution.
○​ Example tools: Burp Suite, OWASP ZAP.
7.​ Security Regression Testing:
○​ Ensures that newly implemented features do not introduce security vulnerabilities
into the system, especially when patches or updates are applied.
8.​ Compliance Testing:
○​ Verifies that the system complies with relevant security regulations and standards,
such as HIPAA for healthcare, PCI-DSS for payment systems, and GDPR for data
protection.

Security Testing Using Python

Python offers a variety of libraries and frameworks that can be leveraged for security testing.
Here are a few examples:

1.​ OWASP ZAP (Zed Attack Proxy):


○​ ZAP can be used for penetration testing and is highly customizable with Python.
It allows you to run automated scans and perform manual security testing.

Example of interacting with ZAP using Python:​


import requests
from zapv2 import ZAPv2

zap = ZAPv2()
target_url = '[Link]
# Start the spider to crawl the target
[Link](target_url)

# Check the alerts for potential vulnerabilities


alerts = [Link](baseurl=target_url)
for alert in alerts:
print(f"Alert: {alert['alert']}, Risk: {alert['risk']}")

2.​ Scapy:
○​ Scapy is a Python library for network packet manipulation and analysis. It is used
in security testing for tasks like sniffing packets, crafting packets for network
penetration testing, and testing for network vulnerabilities.

Example of crafting a SYN packet:​


from [Link] import *

# Craft a SYN packet to initiate a connection


ip = IP(dst="[Link]")
syn = TCP(dport=80, flags="S")
packet = ip/syn
send(packet)

3.​ Requests Library (for Web Vulnerabilities):


○​ The requests library can be used to test for vulnerabilities like SQL injection,
XSS, or CSRF in web applications.

Example of testing for an SQL injection vulnerability:​


import requests

target_url = '[Link]
payload = {'username': 'admin', 'password': "' OR '1'='1"}
response = [Link](target_url, data=payload)

if "Welcome" in [Link]:
print("Potential SQL Injection vulnerability found!")

4.​ PyCrypto:
○​ This library can be used for testing cryptographic security, such as analyzing
encryption algorithms, hashing, and managing keys.

Example of hashing data using SHA256:​


from [Link] import SHA256
data = "password123"
hash_object = [Link]([Link]('utf-8'))
print(hash_object.hexdigest())

Conclusion

Security testing is a vital aspect of software development and maintenance. It helps protect
applications from malicious attacks, ensures data protection, and ensures compliance with
security standards. By using tools and frameworks like OWASP ZAP, Scapy, and PyCrypto in
Python, security professionals can perform thorough assessments and identify potential
vulnerabilities to make the system secure and resilient.
Module 10 - Introduction to Database Testing
1. Introduction to Database Testing

Introduction to Database Testing in Python

Database testing is a critical aspect of verifying that your application interacts correctly with its
underlying database. It involves ensuring that the data retrieval, storage, modification, and
deletion operations are working as expected, and that the database performs optimally under
various conditions. In Python, several libraries and frameworks can be used to carry out effective
database testing, especially in systems where databases play a central role.

What is Database Testing?

Database testing involves validating the data integrity, consistency, and correctness of a database
after performing operations like insertion, update, deletion, and retrieval. It aims to ensure that
the database behaves as expected, adheres to business logic, and maintains the integrity of data
even after interactions from the application.

Why is Database Testing Important?

1.​ Data Integrity: Ensures that data in the database remains accurate, consistent, and
uncorrupted after operations.
2.​ Performance: Verifies that the database handles the volume of requests efficiently,
providing quick query responses.
3.​ Security: Ensures that sensitive data is stored and retrieved securely, preventing
unauthorized access.
4.​ Consistency: Confirms that operations like transactions are properly managed,
maintaining consistency in multi-user or multi-session environments.
5.​ Functionality: Validates that database functions like stored procedures, triggers, and
views are correctly implemented and return the expected results.

Types of Database Testing

1.​ Data Integrity Testing:


○​ Verifies that data is correctly inserted, updated, or deleted and that there are no
discrepancies between the source and the database.
2.​ Database Security Testing:
○​ Ensures that the database is secure against unauthorized access, SQL injection
attacks, and other security risks.
3.​ Performance Testing:
○​ Measures how well the database handles load and large datasets, ensuring it can
scale under stress.
4.​ Transaction Testing:
○​ Tests whether transactions (i.e., groups of database operations) are handled
correctly. This includes verifying ACID (Atomicity, Consistency, Isolation,
Durability) properties.
5.​ Stored Procedure and Trigger Testing:
○​ Ensures that stored procedures, functions, and triggers perform their expected
tasks accurately.
6.​ Schema Testing:
○​ Verifies the schema (tables, relationships, indexes) is designed and structured
correctly.
7.​ SQL Query Testing:
○​ Involves testing SQL queries for correctness, performance, and optimization.

Database Testing Using Python

Python provides several libraries and tools for interacting with databases, executing queries, and
testing database functionality. Some commonly used libraries for database testing include:

1.​ SQLite:
○​ A lightweight, serverless database that comes built-in with Python and is ideal for
simple database testing and prototyping.
2.​ SQLAlchemy:
○​ A powerful ORM (Object Relational Mapper) for working with relational
databases. It supports a variety of databases (MySQL, PostgreSQL, SQLite, etc.)
and is highly flexible.
3.​ PyMySQL:
○​ A library for connecting to MySQL databases and performing various database
operations.
4.​ psycopg2:
○​ A popular PostgreSQL adapter for Python that allows interaction with
PostgreSQL databases.
5.​ unittest or pytest:
○​ Python's built-in testing libraries like unittest or pytest can be used to
write automated tests that check for database functionality, using database
connectors like sqlite3 or SQLAlchemy.

Example of Database Testing Using Python (SQLite)

Here’s an example of how you can perform basic database testing using Python and SQLite:

import sqlite3
import unittest

# Setup SQLite database and table


def setup_database():
conn = [Link](':memory:') # Use in-memory database
for testing
cursor = [Link]()
[Link]('CREATE TABLE users (id INTEGER PRIMARY KEY,
name TEXT, age INTEGER)')
[Link]()
return conn, cursor
# Test class to perform database tests
class TestDatabase([Link]):

def setUp(self):
"""Setup the database for each test"""
[Link], [Link] = setup_database()

def test_insert_data(self):
"""Test inserting data into the database"""
[Link]('INSERT INTO users (name, age)
VALUES (?, ?)', ('Alice', 30))
[Link]()

[Link]('SELECT * FROM users WHERE name=?',


('Alice',))
user = [Link]()

[Link](user[1], 'Alice')
[Link](user[2], 30)

def test_update_data(self):
"""Test updating data in the database"""
[Link]('INSERT INTO users (name, age)
VALUES (?, ?)', ('Bob', 25))
[Link]()
[Link]('UPDATE users SET age=? WHERE
name=?', (26, 'Bob'))
[Link]()

[Link]('SELECT * FROM users WHERE name=?',


('Bob',))
user = [Link]()

[Link](user[2], 26)

def test_delete_data(self):
"""Test deleting data from the database"""
[Link]('INSERT INTO users (name, age)
VALUES (?, ?)', ('Charlie', 40))
[Link]()

[Link]('DELETE FROM users WHERE name=?',


('Charlie',))
[Link]()

[Link]('SELECT * FROM users WHERE name=?',


('Charlie',))
user = [Link]()

[Link](user)

def tearDown(self):
"""Close the database connection after each test"""
[Link]()

# Run the tests


if __name__ == '__main__':
[Link]()

Explanation of the Code:

1.​ setup_database(): Sets up an in-memory SQLite database and creates a users


table.
2.​ TestDatabase class: Uses Python's unittest framework to test various database
operations.
○​ setUp(): Creates a new database connection and cursor before each test.
○​ test_insert_data(): Tests inserting data into the database and verifying it.
○​ test_update_data(): Tests updating existing data in the database and
verifying the changes.
○​ test_delete_data(): Tests deleting data from the database and ensuring it
is removed.
○​ tearDown(): Closes the database connection after each test.

Using SQLAlchemy for Database Testing

If you're using a more complex database setup with SQLAlchemy, here’s how you can test
database operations:

from sqlalchemy import create_engine, Column, Integer, String


from [Link] import declarative_base
from [Link] import sessionmaker
import unittest
Base = declarative_base()

# Define a User model


class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)

# Setup SQLAlchemy engine and session


def setup_database():
engine = create_engine('sqlite:///:memory:') # In-memory
SQLite database
[Link].create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
return engine, session

# Test class for SQLAlchemy database testing


class TestDatabase([Link]):

def setUp(self):
"""Setup the database for each test"""
[Link], [Link] = setup_database()

def test_insert_user(self):
"""Test inserting a user"""
user = User(name="David", age=30)
[Link](user)
[Link]()

# Verify user is inserted


retrieved_user =
[Link](User).filter_by(name="David").first()
[Link](retrieved_user.name, "David")
[Link](retrieved_user.age, 30)

def tearDown(self):
"""Close the session after each test"""
[Link]()

# Run the tests


if __name__ == '__main__':
[Link]()

Conclusion

Database testing ensures that your system interacts correctly with its database, maintaining data
integrity, security, and performance. By using Python libraries such as sqlite3,
SQLAlchemy, and unittest, you can automate and streamline database testing to validate
database operations and ensure the correctness of your data-driven applications.
Module 11 - Introduction to Mobile Application Testing
1. Introduction to Mobile Application Testing
a)​ Type of mobile platform [Android, iOS]
b)​ Introduction to SDK tools like adb, ddms etc

Introduction to Mobile Application Testing in Python

Mobile application testing ensures that an application performs as expected on mobile platforms,
providing a smooth user experience, correct functionality, and reliable performance. Python can
be used for mobile application testing by leveraging various tools, libraries, and frameworks to
automate testing processes across both Android and iOS platforms.

Types of Mobile Platforms: Android & iOS

Mobile applications are primarily built for two types of platforms:

1.​ Android:
○​ Developed by Google, Android is an open-source operating system for mobile
devices, with a wide variety of devices from different manufacturers running
Android.
○​ Most Android apps are written in Java, Kotlin, or C++ and run on the Android
runtime (ART).
2.​ iOS:
○​ Developed by Apple, iOS is a closed-source operating system used exclusively on
Apple devices like iPhones, iPads, and iPod Touch.
○​ iOS applications are usually written in Swift or Objective-C and are run on the
iOS runtime.

Mobile Application Testing with Python

Python can be used to automate testing for both Android and iOS apps by leveraging tools and
frameworks designed for mobile automation testing. The most popular ones include:
1.​ Appium:
○​ Appium is an open-source, cross-platform mobile automation framework that
supports both Android and iOS. It allows writing tests using Python (and several
other programming languages) and can interact with native and hybrid apps.
2.​ Selendroid:
○​ Selendroid is a test automation framework for Android devices that allows testing
Android apps. While it mainly works with Android, it is compatible with Appium
to enable cross-platform testing.
3.​ UIAutomator (for Android):
○​ UIAutomator is a Google testing framework for Android that allows automated
testing of apps' user interfaces.
4.​ XCUITest (for iOS):
○​ XCUITest is Apple's framework for automating UI tests on iOS applications.
Though primarily for use with Xcode, it can be accessed via Python using
bindings or third-party libraries.
5.​ Pytest:
○​ Pytest is a testing framework that can be used with Appium and other tools for
running tests on mobile apps. It allows organizing test cases, reporting, and test
execution.

Types of Mobile Application Tests

1.​ Functional Testing:


○​ Ensures that the app's features work as expected and provides the expected
functionality for the end user. This includes user interactions like button presses,
text input, navigation, and more.
2.​ UI/UX Testing:
○​ Ensures that the user interface is consistent and responsive on various screen
sizes, orientations, and devices. The user experience is tested for ease of use, flow,
and intuitiveness.
3.​ Performance Testing:
○​ Evaluates how well the app performs under various conditions, such as with high
traffic, limited resources, or on older devices. This includes tests for app launch
time, battery consumption, memory usage, and network speed.
4.​ Security Testing:
○​ Ensures that the app is secure from potential threats, including data breaches,
encryption weaknesses, and vulnerability to external attacks.
5.​ Compatibility Testing:
○​ Ensures that the app works on a wide range of devices, screen resolutions, and
operating systems. This includes testing on different versions of Android and iOS.
6.​ Regression Testing:
○​ Ensures that new changes or updates to the app don’t break existing functionality.
7.​ Accessibility Testing:
○​ Ensures that the app is accessible to people with disabilities, including testing
screen reader compatibility and adherence to accessibility guidelines.

Introduction to SDK Tools for Mobile Testing

In mobile app testing, SDK (Software Development Kit) tools are essential for interacting with
the mobile device, automating tasks, and debugging the app. Some of the key SDK tools used in
mobile testing are:

1.​ Android Debug Bridge (ADB):


○​ ADB is a command-line tool that allows developers and testers to interact with
Android devices. It is used for installing, debugging, and managing apps on
Android devices.
○​ Common ADB commands for testing:
■​ adb devices: List all connected Android devices.
■​ adb install <apk_file>: Install an APK file onto the device.
■​ adb logcat: View logs of the device, which is useful for debugging.
■​ adb shell: Run shell commands on the device.
Example usage of ADB in Python:​
import os
[Link]('adb devices') # List connected Android devices
[Link]('adb logcat') # View logs on an Android device

2.​ Dalvik Debug Monitor Service (DDMS):


○​ DDMS is a tool for debugging Android applications. It provides functionalities
such as monitoring logs, managing device connections, screen recording, taking
screenshots, and more.
○​ DDMS is now integrated into Android Studio, but it is still used as a standalone
tool in some cases for debugging and performance monitoring.
3.​ Appium:
○​ Appium is a cross-platform tool that supports Android and iOS testing. It works
by communicating with the mobile device via its respective drivers (Android
driver for Android and iOS driver for iOS).
○​ Appium allows writing tests in multiple programming languages, including
Python.

Example of running an Appium test in Python (install Appium-Python-Client):​


from appium import webdriver

desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "Android Emulator",
"app": "/path/to/your/[Link]"
}

driver = [Link]("[Link]
desired_caps)
[Link]()

4.​ Xcode Command Line Tools (for iOS):


○​ Xcode provides command-line tools for interacting with iOS devices and
simulators, such as xcrun, xcodebuild, and instruments.
○​ These tools can be used for automating testing on iOS devices, including UI
testing with XCUITest.
5.​ Fastlane:
○​ Fastlane is an open-source automation tool that allows you to automate tasks like
beta deployment, app store submission, and testing across Android and iOS
platforms.
6.​ MonkeyRunner (for Android):
○​ MonkeyRunner is a tool that provides APIs for writing programs to control
Android devices. It can be used for automating UI testing on Android apps.

Example of Mobile Testing with Appium in Python

Appium is widely used for mobile application testing. Here’s an example of how to write a test
for an Android app using Appium in Python:

Install Appium and Appium-Python-Client:​


pip install Appium-Python-Client
Write a test to launch the app and perform a simple action like clicking a button:​
from appium import webdriver
from time import sleep

# Define desired capabilities


desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "Android Emulator",
"app": "/path/to/your/[Link]",
"automationName": "UiAutomator2"
}

# Initialize Appium driver


driver = [Link]("[Link]
desired_caps)

# Find the button by its ID and click it


button = driver.find_element_by_id("[Link]:id/button")
[Link]()

# Wait for a few seconds


sleep(5)

# Close the app


[Link]()
Conclusion

Mobile application testing ensures that an app delivers a smooth, secure, and bug-free experience
for users. Python, with the help of tools like Appium, ADB, and Xcode, allows developers and
testers to automate tests for both Android and iOS applications. By leveraging SDK tools and
testing frameworks, mobile app testing becomes efficient and effective, ensuring apps perform
well under various conditions.
Module 12 - Agile Model
1. Scrum
2. Sprint
3. User Story

Agile Model in Python

Agile is a popular project management and software development methodology that emphasizes
flexibility, collaboration, customer feedback, and rapid delivery of small, incremental changes to
software. The Agile model consists of several frameworks, and Scrum is one of the most widely
used frameworks within Agile. Below, we will explain key concepts such as Scrum, Sprint, and
User Story, along with their application in Python development.

1. Scrum

Scrum is an Agile framework used to manage and complete complex projects. It is based on a
set of roles, events, and artifacts that allow teams to deliver working software frequently and
iteratively. Scrum emphasizes collaboration, flexibility, and transparency within the development
team and stakeholders.

Scrum Key Components:

●​ Roles:
○​ Product Owner: Responsible for managing the product backlog, ensuring the
right features are prioritized.
○​ Scrum Master: Facilitates Scrum processes, removes obstacles, and ensures that
the team follows Scrum practices.
○​ Development Team: A cross-functional team responsible for delivering the
product increment.
●​ Events:
○​ Sprint Planning: A meeting to define the work to be completed during the sprint.
○​ Daily Scrum: A daily stand-up meeting to discuss progress, obstacles, and
upcoming work.
○​ Sprint Review: A meeting at the end of the sprint to showcase completed work to
stakeholders.
○​ Sprint Retrospective: A meeting to reflect on the sprint and identify
improvements for the next sprint.
●​ Artifacts:
○​ Product Backlog: A prioritized list of all desired work for the product.
○​ Sprint Backlog: The list of tasks to be completed during the sprint, taken from
the product backlog.
○​ Increment: The working software delivered at the end of each sprint.

Python Example (Scrum Board): A Scrum board helps track tasks, their progress, and their
statuses during the sprint. Here’s an example of how we might structure a Scrum board in Python
using a simple dictionary to track tasks:

# Scrum board in Python for a Sprint


sprint_backlog = {
"task_1": {"title": "Implement login functionality",
"status": "To Do"},
"task_2": {"title": "Create user registration page",
"status": "In Progress"},
"task_3": {"title": "Set up database schema", "status":
"Done"}
}

def update_task_status(task_id, new_status):


if task_id in sprint_backlog:
sprint_backlog[task_id]["status"] = new_status
else:
print("Task not found!")
# Example usage:
update_task_status("task_2", "Done")
print(sprint_backlog)

2. Sprint

A Sprint is a time-boxed iteration (usually 1-4 weeks) in Scrum during which a specific set of
work (items from the product backlog) is completed and turned into a deliverable increment. The
sprint starts with a Sprint Planning meeting and ends with a Sprint Review and Sprint
Retrospective.

Sprint Key Characteristics:

●​ A defined Sprint Goal is set to focus on achieving specific objectives.


●​ Work is pulled from the Sprint Backlog, which is a subset of the Product Backlog.
●​ At the end of the sprint, a Deliverable Increment of software is produced.

Python Example (Simulating a Sprint): We can simulate the process of completing tasks in a
sprint using Python. Below is an example where tasks are completed within a sprint, and their
statuses are updated:

# Define a Sprint with tasks


sprint = {
"task_1": {"title": "Implement login functionality",
"status": "To Do"},
"task_2": {"title": "Create user registration page",
"status": "To Do"},
"task_3": {"title": "Set up database schema", "status": "To
Do"}
}
def start_sprint(sprint):
print("Sprint started!")
for task_id, task in [Link]():
print(f"Working on {task['title']}...")
# Simulate task completion
sprint[task_id]["status"] = "Done"
print(f"{task['title']} completed!")

start_sprint(sprint)
print(sprint)

3. User Story

A User Story is a brief description of a feature or functionality written from the perspective of
the end user. It defines the feature's behavior, purpose, and value to the user. In Scrum, user
stories are part of the product backlog, and they are prioritized by the product owner.

User Story Template:

As a [role], I want [feature] so that [benefit].

Example of User Story:

●​ "As a user, I want to log in to my account so that I can access personalized content."

User Story Key Elements:

●​ Acceptance Criteria: Clear conditions that define when a user story is considered
complete and functioning correctly.
●​ Priority: How important the user story is to the product’s success.
●​ Story Points: A relative measure of the effort required to implement the user story (often
based on complexity or time).
Python Example (Managing User Stories): In a Python-based system, we can store and
manage user stories with attributes like title, description, and acceptance criteria. Here's how to
manage a few user stories in Python:

class UserStory:
def __init__(self, title, description, acceptance_criteria):
[Link] = title
[Link] = description
self.acceptance_criteria = acceptance_criteria
[Link] = "To Do"

def __str__(self):
return f"User Story: {[Link]}, Status:
{[Link]}"

# Create user stories


user_stories = [
UserStory("Login Feature", "As a user, I want to log in so
that I can access my account", "Valid username and password"),
UserStory("User Registration", "As a new user, I want to
register so that I can create an account", "Form validation and
email confirmation")
]

# Mark a user story as complete


def mark_user_story_done(user_story):
user_story.status = "Done"
# Example usage
for us in user_stories:
print(us)
mark_user_story_done(us)

print("\nAfter completion:")
for us in user_stories:
print(us)

Conclusion

In Agile development using Scrum, the key concepts of Scrum, Sprint, and User Story are
central to ensuring successful project management and timely delivery of features. Python can be
used to automate, manage, and track Scrum processes, including sprint backlogs, user stories,
and task completion. By adopting Agile practices and leveraging tools like Python, teams can
stay organized, responsive to changes, and focused on delivering valuable software
incrementally.
Module 13 - Regression Testing
1. What is regression testing?
2. How to prepare test cases for regression testing

Regression Testing in Python

Regression Testing is a type of software testing that ensures that recent changes (such as bug
fixes, new features, or updates) in the software application have not adversely affected the
existing functionality of the application. The goal is to confirm that the new code or functionality
does not introduce new bugs or break the already working parts of the software.

Key Points of Regression Testing:

●​ Ensures stability: Ensures that updates and changes do not negatively impact existing
functionality.
●​ Automated Testing: Regression tests can often be automated to run quickly after every
change, making it easier to verify the stability of the application.
●​ Covers wide functionality: While it focuses on checking previously tested functionality,
it may also cover new features that interact with the old functionality.

Regression testing typically involves running a set of test cases that cover:

1.​ Core functionalities that should work even after the changes.
2.​ Previously reported bugs to confirm that they are fixed and haven’t reappeared.
3.​ New features that integrate with existing parts of the software.

How to Prepare Test Cases for Regression Testing

Preparing test cases for regression testing is crucial to ensure comprehensive testing of the
existing application while focusing on the areas that might have been impacted by recent
changes.

Here’s how to prepare effective regression test cases:


1. Identify Core Features of the Application

●​ Focus on the most critical and frequently used parts of the application that are likely to be
impacted by any change (such as login, data entry, and basic navigation).
●​ These test cases should be reusable and should ideally cover the most basic and essential
functionality.

2. Prioritize Test Cases

●​ Prioritize test cases based on the importance of the feature and the risk of impact. For
example, a login functionality or payment gateway should be tested more frequently than
other less critical features.
●​ Consider using techniques like Risk-Based Testing to focus on areas that are more likely
to break.

3. Use a Test Case Template

●​ A clear and consistent format for regression test cases is essential. Below is a typical
regression test case template:

Test Test Case Preconditions Test Steps Expected Status


Case Title Result
ID

TC01 Verify Login User has an 1. Open login page User is Passed/Faile
Functionality account 2. Enter valid redirected to d
credentials 3. Click the
on the login button dashboard

4. Select Areas Affected by Recent Changes

●​ Track recent changes in the application (such as bug fixes, new features, or
enhancements).
●​ Focus on testing areas that might have been affected by these changes. If a bug is fixed in
one area of the application, run tests on related areas as well to ensure no new issues are
introduced.

5. Automate Regression Test Cases

●​ Given that regression tests are often repeated after every change, automating these tests
can save time and resources. Python, combined with testing frameworks like PyTest or
unittest, allows for the automation of regression test cases.

Example using unittest in Python:

import unittest

# Sample test class for a simple login functionality


class TestLoginFunctionality([Link]):

def test_valid_login(self):
username = "test_user"
password = "valid_password"
[Link]([Link](username, password))

def test_invalid_login(self):
username = "test_user"
password = "invalid_password"
[Link]([Link](username, password))

# Mockup of a simple login function


def login(self, username, password):
# Simulate login process
valid_user = "test_user"
valid_password = "valid_password"
return username == valid_user and password ==
valid_password

# Run the tests


if __name__ == "__main__":
[Link]()

6. Consider Regression Testing on Multiple Environments

●​ Ensure that your regression test cases are tested across multiple environments, such as
different browsers, devices, operating systems, or different versions of the application.

7. Check for Data Integrity and Workflow

●​ Ensure that the core workflows and data integrity remain intact. If there are data-driven
operations in your application (such as adding, updating, or deleting records), make sure
to test these scenarios.

8. Version Control

●​ Keep track of the version of the test cases to ensure that the right test cases are being
executed after each version release. Keep your test cases updated according to the new
changes in the code.

9. Document Test Results and Identify Failures

●​ Document the results of each regression test carefully. For any failure, provide details
about the issue and steps for resolution. This helps in debugging and tracking known
issues.

10. Test on both Positive and Negative Scenarios


●​ Always test both positive and negative scenarios. Ensure that valid inputs work as
expected and that invalid inputs or edge cases do not break the application.

Example of Regression Testing with PyTest

Let’s take an example of a regression test case where we verify the login functionality.

Test Case Scenario: Verify Login Functionality (Regression)

●​ Functionality: Ensure that the login functionality is not broken after recent changes.
●​ Test Steps:
1.​ Open the login page.
2.​ Enter valid login credentials (username and password).
3.​ Click the login button.
4.​ Verify that the user is redirected to the dashboard page.

PyTest Code Example:

import pytest
# Sample function simulating login process
def login(username, password):
valid_username = "test_user"
valid_password = "password123"
if username == valid_username and password ==
valid_password:
return True
return False

# Regression test case to verify the login functionality


@[Link]
def test_valid_login():
assert login("test_user", "password123") == True, "Login
should be successful"

@[Link]
def test_invalid_login():
assert login("test_user", "wrong_password") == False, "Login
should fail with incorrect password"
@[Link]
def test_empty_username():
assert login("", "password123") == False, "Login should fail
with empty username"
@[Link]
def test_empty_password():
assert login("test_user", "") == False, "Login should fail
with empty password"

Running the Tests:

To run the regression tests using PyTest, you can use the following command:

pytest --mark regression

This will run only the regression tests marked with @[Link].

Conclusion

Regression testing is crucial to ensure that changes in the software do not introduce new defects
and that the existing functionality is preserved. By preparing structured and prioritized test cases,
automating tests using tools like PyTest or unittest, and focusing on key areas of the application,
you can make regression testing more efficient and effective. With Python, you can streamline
the testing process and quickly verify that the software remains stable after each change.
Module 14 - Test Case
1. How to write good quality test case

Writing good quality test cases in Python is essential for ensuring that your code is reliable,
maintainable, and efficient. A well-written test case will make it easier to detect defects early in
the development process, reduce maintenance overhead, and increase the overall quality of the
software.

Here are the key practices for writing high-quality test cases in Python:

1. Follow a Clear Test Case Structure

A well-structured test case will help you and others quickly understand what is being tested, how
it is tested, and what the expected results are.

A typical test case structure includes:

●​ Test Case ID: A unique identifier for the test case.


●​ Test Case Title: A brief description of the test.
●​ Preconditions: Any setup or conditions that must be met before the test is run.
●​ Test Steps: Detailed steps on how to execute the test.
●​ Test Data: Inputs needed for the test.
●​ Expected Result: What the test should verify.
●​ Actual Result: The result observed after running the test.
●​ Status: Pass/Fail based on the outcome.

2. Write Clear and Descriptive Test Case Names

Test case names should be clear, descriptive, and follow a consistent naming convention. They
should convey what the test is verifying and under what condition.

For example:

def test_valid_login_with_correct_credentials():
# Test for successful login with valid credentials
pass

def test_invalid_login_with_incorrect_password():
# Test for unsuccessful login with incorrect password
pass

The name should clearly describe:

●​ What functionality is being tested (e.g., login functionality).


●​ The expected outcome or behavior (e.g., successful login, invalid password).

3. Keep Tests Isolated and Independent

Each test case should be independent of others. It should not rely on the outcome of another test.
This helps avoid cascading failures and makes it easier to identify issues when they arise.

Example:

def test_add_two_numbers():
assert add(1, 2) == 3

def test_subtract_two_numbers():
assert subtract(5, 3) == 2

Each test case should be isolated, and changes in one test should not affect other tests.

4. Follow the Arrange-Act-Assert Pattern

A good test case follows the Arrange-Act-Assert (AAA) pattern, which provides a clear
structure for setting up the test, performing the action, and verifying the outcome:

1.​ Arrange: Prepare the data and the environment.


2.​ Act: Call the function or method that is being tested.
3.​ Assert: Verify that the outcome is correct.

Example:

def test_addition_of_two_numbers():
# Arrange
a = 5
b = 3
expected_result = 8

# Act
result = add(a, b)

# Assert
assert result == expected_result, f"Expected
{expected_result}, but got {result}"

This pattern helps organize the test and makes it easier to understand the flow.

5. Use Meaningful Assertions

The assert statement is used to verify that the actual result matches the expected result. A
meaningful assertion helps identify the problem quickly when the test fails.

●​ Good assertion:

assert result == expected_value, f"Expected {expected_value},


but got {result}"

●​ Bad assertion:

assert result
The first example gives a clear explanation in case of failure, making it easier to debug. The
second example is vague and does not provide helpful information.

6. Cover Positive and Negative Test Cases

Ensure that you cover both positive and negative test cases:

●​ Positive Test Case: Verifies that the system behaves as expected under valid conditions.
●​ Negative Test Case: Verifies that the system handles invalid input or unexpected
conditions correctly.

Example:

def test_valid_email():
assert is_valid_email("user@[Link]") is True

def test_invalid_email():
assert is_valid_email("user@.com") is False

By testing both valid and invalid scenarios, you ensure that your code can handle all possible
situations.

7. Handle Edge Cases

Make sure you test edge cases, which are often where bugs occur. Edge cases may involve
testing extreme values, large inputs, or boundary conditions.

Example:

def test_large_number_addition():
large_number = 10**12
assert add(large_number, 1) == large_number + 1

def test_empty_string():
assert reverse_string("") == ""

Edge cases might not always be obvious, so carefully consider the inputs that might break the
system.

8. Keep Tests Short and Focused

Each test case should focus on one specific behavior. Avoid writing tests that are too broad or try
to test multiple functionalities in one test case.

For example:

def test_login_with_correct_credentials():
assert login("user", "password") == "Login successful"

def test_login_with_incorrect_credentials():
assert login("user", "wrong_password") == "Login failed"

In this example, each test focuses on a single condition (valid or invalid login), making the test
clear and easy to maintain.

9. Use Mocks and Stubs for External Dependencies

If your code interacts with external systems like databases, APIs, or third-party services, use
mocks and stubs to simulate these interactions during testing. This avoids hitting real external
resources and allows tests to run independently of external systems.

Example using [Link]:

from [Link] import patch

def test_get_user_data():
with patch('module_name.get_data_from_api') as mock_api:
mock_api.return_value = {"id": 1, "name": "John Doe"}
result = get_user_data(1)
assert result == {"id": 1, "name": "John Doe"}

In this example, get_data_from_api is mocked to return a predefined response.

10. Write Tests that Are Easy to Maintain

Ensure your tests are maintainable by keeping them simple and clean. If the code changes, the
test should be easy to update. Write test cases that will be reusable in the future and don’t require
frequent changes when the code evolves.

●​ Avoid hardcoding values: Use variables or constants to make the test more flexible.
●​ Keep test data organized and externalized where appropriate.

Example:

# Good Practice: Define test data as variables


valid_user_data = {"username": "test_user", "password":
"password123"}

def test_login():
result = login(valid_user_data["username"],
valid_user_data["password"])
assert result == "Login successful"

Example of Good Quality Test Case in Python using unittest


import unittest

class TestMathOperations([Link]):
def test_addition(self):
# Arrange
a = 10
b = 5
expected_result = 15

# Act
result = a + b

# Assert
[Link](result, expected_result)

def test_division(self):
# Arrange
a = 10
b = 2
expected_result = 5

# Act
result = a / b

# Assert
[Link](result, expected_result)

def test_division_by_zero(self):
# Arrange
a = 10
b = 0

# Act & Assert


with [Link](ZeroDivisionError):
a / b
if __name__ == "__main__":
[Link]()
Conclusion

To write good quality test cases in Python:

●​ Follow a clear and consistent structure.


●​ Write descriptive names and focus on one functionality per test.
●​ Use assertions that provide clear information when a test fails.
●​ Consider edge cases, negative test cases, and external dependencies.
●​ Keep tests simple, maintainable, and automated where possible.

By applying these best practices, you can create high-quality test cases that improve the
reliability and maintainability of your software.
Module 15 - Defect
1. How to write a good quality defect?

Writing a good quality defect report (also called a bug report) is crucial for effective
communication between developers, testers, and other stakeholders. A well-written defect report
helps in quickly understanding the issue, reproducing it, and resolving it efficiently.

Here’s how to write a good quality defect report in Python (or for any software project):

Key Elements of a Good Defect Report

1.​ Defect ID
○​ A unique identifier for the defect. This helps in tracking and referencing the issue
across tools or conversations.

Example:

○​ Defect ID: BUG-1234


2.​ Summary/Title
○​ A concise and clear description of the defect. The title should briefly indicate the
issue.

Example:

○​ Summary: "Login page throws 500 error on valid credentials."


3.​ Description
○​ A detailed description of the defect. This should include information about what
the bug is, what it affects, and where it occurs. Provide context for others to
understand the nature of the defect.

Example:

○​ Description: "When a user enters valid login credentials (username: test_user,


password: password123), the login page throws a 500 Internal Server Error and
prevents the user from logging in."
4.​ Steps to Reproduce
○​ A clear, step-by-step guide to reproduce the defect. This helps developers or
testers reproduce the issue in their environment.

Example:

○​ Steps to Reproduce:
■​ Open the application login page.
■​ Enter username: test_user.
■​ Enter password: password123.
■​ Click the "Login" button.
■​ Observe the 500 error displayed.
5.​ Expected Result
○​ What the behavior should be if the software is working correctly. This helps in
determining if the defect is caused by incorrect behavior.

Example:

○​ Expected Result: "The user should be redirected to the dashboard upon


successful login."
6.​ Actual Result
○​ What actually happens when the defect occurs. This should clearly describe the
observed behavior, especially the error message or unexpected behavior.

Example:

○​ Actual Result: "Instead of logging in, the page displays a 500 Internal Server
Error."
7.​ Severity/Priority
○​ Severity: The impact of the defect on the system's functionality. Is it a major issue
or a minor issue?
■​ High: The defect causes a critical issue (e.g., system crash, data loss).
■​ Medium: The defect affects non-critical features.
■​ Low: The defect is minor, such as UI glitches.
○​ Priority: The urgency of fixing the defect based on its severity and business
needs.
■​ High: Needs to be fixed immediately (e.g., blocking major functionality).
■​ Medium: Should be fixed soon but does not block core functionality.
■​ Low: Can be fixed later.

Example:

○​ Severity: High
○​ Priority: High
8.​ Environment/Configuration
○​ The environment in which the defect was found. This can include details about
the platform, browser, operating system, software version, or hardware where the
defect occurs.

Example:

○​ Environment:
■​ OS: Windows 10
■​ Browser: Google Chrome (version 91)
■​ Application Version: 1.0.0
■​ Database: MySQL 8.0
9.​ Attachments (Logs, Screenshots, or Videos)
○​ Include any relevant files that can help in reproducing the defect or diagnosing the
issue. This can include:
■​ Screenshots of the error message.
■​ Log files or stack traces.
■​ Videos showing the issue happening in real-time.

Example:

○​ Attachment: Screenshot of the 500 error page.


○​ Attachment: Server log file showing the exception stack trace.
10.​Possible Root Cause (Optional)
○​ If you have any insights into what might be causing the defect (e.g., an issue in a
particular function or class), mention it here. This is especially useful if the tester
has knowledge of the codebase.

Example:

○​ Possible Root Cause: "The issue may be related to an exception occurring in the
database connection during the authentication process."
11.​Additional Notes/Comments
○​ Any extra information that may help resolve the defect. This could include:
■​ Related issues (e.g., previously reported bugs).
■​ Potential workarounds.
■​ Information about the frequency or consistency of the defect.

Example:

○​ Additional Notes: "This error only occurs when logging in with valid credentials,
not for invalid credentials."

Example of a Good Defect Report

Here’s an example of a well-written defect report in Python:

Defect ID: BUG-1234

Summary: Login page throws 500 error on valid credentials.

Description: When a user enters valid login credentials (username: test_user, password:
password123), the login page throws a 500 Internal Server Error and prevents the user from
logging in. This issue seems to occur only for valid credentials, and the error message does not
provide any useful information.

Steps to Reproduce:
1.​ Open the application login page.
2.​ Enter username: test_user.
3.​ Enter password: password123.
4.​ Click the "Login" button.
5.​ Observe the 500 error displayed.

Expected Result: The user should be redirected to the dashboard upon successful login.

Actual Result: Instead of logging in, the page displays a 500 Internal Server Error.

Severity: High​
Priority: High

Environment:

●​ OS: Windows 10
●​ Browser: Google Chrome (version 91)
●​ Application Version: 1.0.0
●​ Database: MySQL 8.0

Attachments:

●​ Screenshot of the error.


●​ Server log showing the exception.

Possible Root Cause: The issue may be related to a failed database connection during the
authentication process, causing a server-side exception.

Additional Notes:

●​ This issue does not occur for invalid login attempts, where the user is correctly shown an
error message for invalid credentials.
●​ Error appears intermittently for valid logins.
Tips for Writing Good Defect Reports:

●​ Be Clear and Concise: The defect report should be easy to read and understand. Avoid
jargon or ambiguous statements.
●​ Reproducibility: Ensure that anyone reading the defect report can easily reproduce the
issue by following the steps outlined.
●​ Focus on Impact: Describe how the defect impacts the user or system functionality.
●​ Provide Evidence: Whenever possible, include logs, screenshots, or any other evidence
that can help reproduce or investigate the defect.
●​ Avoid Assumptions: Do not assume what caused the issue unless you are certain. Stick
to the facts and observable behavior.

By following these guidelines, you will write defect reports that are clear, actionable, and helpful
to the development team, which ultimately speeds up the resolution process.

Common questions

Powered by AI

Mocking improves unit tests by simulating interactions with external systems, such as databases or APIs, making tests more predictable and faster. It allows developers to focus on testing the logic of the code without relying on actual external resources. By using mocking tools like unittest.mock, developers can ensure tests remain independent and accurately verify interactions, reducing potential side-effects from external dependencies during testing .

Ensuring test cases remain effective involves regular review and updates to align with changes in project requirements. Clear and concise documentation, including detailed steps, preconditions, and expected results, is crucial for test management. Additional practices include reviewing test cases after code changes or defects have been addressed, and utilizing test management tools like Jira for organizing and categorizing test cases based on priorities or features. Automation and integration with CI/CD pipelines also help maintain test relevance .

In test management, a Test Case in tools like Jira involves defining a set of conditions and inputs to verify if specific functionalities work as intended, including preconditions, steps, and expected results. Conversely, a Bug Report in Bugzilla focuses on documenting unexpected behaviors, including descriptions, reproducible steps, and the issue's impact. Test Cases ensure functionalities meet requirements, while Bug Reports document discrepancies for resolution .

Test environment setup intersects with risk management by ensuring that testing conditions mimic production environments to accurately identify potential issues. Effective risk management involves anticipating and mitigating risks, such as test environment unavailability or unresolved issues from previous versions. Strategies include setting up backup environments and allocating extra resources to handle critical defects, which helps mitigate delays and improve test reliability .

Parameterized tests in Python allow the execution of a single test with multiple sets of inputs, improving test coverage and efficiency. This method reduces the need to write separate test cases for each input set and ensures consistent test execution across different scenarios. Using decorators like @pytest.mark.parametrize in pytest, developers can test functions with various inputs and expected outcomes, verifying that implementations are robust and handle diverse inputs correctly .

CI/CD pipelines automate the process of software integration and delivery, playing a crucial role in Agile by facilitating frequent releases and deployments. This integration allows developers to consistently merge code changes, run tests, and deploy to production environments, enhancing the ability to quickly respond to feedback and changes. CI/CD supports Agile’s iterative nature by ensuring that deployments are smooth, tested, and aligned with user requirements .

Using descriptive test names enhances test management by clearly communicating the purpose and scope of the test, making it easier for developers to understand functionality coverage at a glance. This practice aids in quickly identifying failed tests, understanding issues, maintaining tests over time, and improving collaboration among team members. Descriptive names contribute to self-documenting tests, fostering maintainability and readability in complex projects .

Continuous testing in Agile allows for early detection of bugs, which reduces costs and improves quality by integrating tests into each sprint. This contrasts with the Waterfall model, where testing is performed at the end of the project, increasing the risk of late discovery of major issues. Agile’s approach enables more frequent and reliable feedback loops, decreasing deployment risks and leading to faster time-to-market .

TDD aligns with Agile methodologies due to its focus on continuous integration and iterative development. In TDD, writing tests before code encourages more frequent testing cycles and immediate feedback, which supports Agile’s iterative nature and frequent releases. This approach minimizes bugs and aligns closely with Agile's goal of rapid responses to changing requirements, ensuring continuous improvement and customer satisfaction .

Python supports various stages of the STLC through its ecosystem of libraries and tools. For Requirement Analysis, libraries like PyPDF2 and SQLite can parse documents and test database-specific requirements. In Test Planning, the Jira-Python API helps manage plans and tasks. Python-based frameworks like unittest and pytest are used for Test Case Development and Execution, enabling both manual and automated testing. Mock or responses can simulate external system interactions, aiding Test Environment Setup. This integrative capability of Python enhances robustness throughout the STLC .

You might also like