Skip to content

Latest commit

 

History

History
296 lines (231 loc) · 8.76 KB

File metadata and controls

296 lines (231 loc) · 8.76 KB

Comprehensive Python Testing Strategies

Slide 1: Happy Path Testing

Happy path testing involves testing the primary use case or the most common scenario of an application or a function. It ensures that the code works as expected under normal circumstances.

def calculate_area(length, width):
    """
    Calculates the area of a rectangle.
    """
    return length * width

# Test case for happy path
def test_calculate_area_happy_path():
    length = 5
    width = 3
    expected_area = 15
    assert calculate_area(length, width) == expected_area

Slide 2: Edge Case Testing

Edge cases are inputs or scenarios that are valid but outside the expected or common use cases. They test the boundaries of the system or function.

def validate_age(age):
    """
    Validates if the age is between 0 and 120.
    """
    if age < 0 or age > 120:
        raise ValueError("Age must be between 0 and 120")
    return True

# Test cases for edge cases
def test_validate_age_edge_cases():
    assert validate_age(0) is True
    assert validate_age(120) is True
    assert validate_age(-1) is False
    assert validate_age(121) is False

Slide 3: Negative Test Cases

Negative test cases are scenarios where the input is invalid or unexpected. They help catch bugs and ensure the code handles errors and exceptions correctly.

def divide_numbers(a, b):
    """
    Divides two numbers and returns the result.
    """
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    return a / b

# Test case for negative scenario
def test_divide_numbers_negative():
    with pytest.raises(ZeroDivisionError):
        divide_numbers(10, 0)

Slide 4: Security and Illegal Input Testing

Security testing ensures that the application or function is secure against potential threats, such as SQL injection, cross-site scripting (XSS), and other vulnerabilities. Illegal input testing checks how the code handles invalid or malicious inputs.

import re

def sanitize_input(user_input):
    """
    Sanitizes user input to prevent XSS attacks.
    """
    return re.sub(r'<script>.*?</script>', '', user_input, flags=re.DOTALL)

# Test case for XSS attack
def test_sanitize_input_xss():
    malicious_input = "<script>alert('XSS Attack')</script>"
    sanitized_input = sanitize_input(malicious_input)
    assert sanitized_input == ""

Slide 5: Sankey Diagrams

Sankey diagrams are a specific type of flow diagram that visualizes the flow of data or quantities through a system or process. They can be useful for understanding and testing complex systems or data pipelines.

import matplotlib.pyplot as plt
import pandas as pd

data = pd.DataFrame({
    'Source': ['A', 'A', 'B', 'C'],
    'Target': ['B', 'C', 'D', 'D'],
    'Value': [5, 3, 1, 2]
})

# Create a Sankey diagram
fig = plt.figure()
sankey = Sankey(flows=data, labels=['A', 'B', 'C', 'D'], orientations=[0, 1, 0, -1])
sankey.add(flows=data['Value'], alpha=0.5)
sankey.finish()
plt.show()

Slide 6: Test Driven Development (TDD)

Test-Driven Development (TDD) is a software development approach where tests are written before the actual code. It helps ensure the code is testable and encourages modular, maintainable design.

# Test case for a function to calculate the factorial of a number
def test_factorial():
    assert factorial(0) == 1
    assert factorial(1) == 1
    assert factorial(5) == 120
    assert factorial(-1) is None  # Negative numbers should return None

# Implementation of the factorial function
def factorial(n):
    if n < 0:
        return None
    elif n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n - 1)

Slide 7: Mocking and Stubbing

Mocking and stubbing are techniques used in unit testing to isolate the code under test from its dependencies. Mocks simulate the behavior of external resources or components, while stubs provide predetermined responses to function calls.

import unittest
from unittest.mock import patch, Mock

class TestMyClass:
    @patch('module.external_function')
    def test_my_function(self, mock_external_function):
        mock_external_function.return_value = 42
        result = my_class.my_function()
        assert result == 42
        mock_external_function.assert_called_once()

    @patch('module.external_resource')
    def test_my_other_function(self, mock_external_resource):
        mock_resource = Mock()
        mock_external_resource.return_value = mock_resource
        my_class.my_other_function()
        mock_resource.some_method.assert_called_once()

Slide 8: Parameterized Testing

Parameterized testing is a technique where a single test case is executed multiple times with different input data sets. This helps reduce code duplication and ensures thorough testing of various scenarios.

import pytest

@pytest.mark.parametrize("input_data, expected_output", [
    ([1, 2, 3], 6),
    ([-2, 4, -1], 1),
    ([], 0),
    ([1.5, 2.7, 3.8], 8.0)
])
def test_sum_list(input_data, expected_output):
    assert sum(input_data) == expected_output

Slide 9: Code Coverage

Code coverage is a measure of how much of the codebase is executed by the test suite. It helps identify untested or missing code paths and ensures adequate testing coverage.

# Example function to calculate the factorial of a number
def factorial(n):
    if n < 0:
        return None
    elif n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n - 1)

# Test case for the factorial function
def test_factorial():
    assert factorial(0) == 1
    assert factorial(1) == 1
    assert factorial(5) == 120
    assert factorial(-1) is None

Slide 10: Integration Testing

Integration testing is a type of testing that verifies the proper interaction and communication between different components or modules of a system.

import requests

def test_api_integration():
    # Set up test data
    payload = {'name': 'John Doe', 'email': 'john@example.com'}

    # Send a POST request to create a new user
    response = requests.post('https://api.example.com/users', json=payload)
    assert response.status_code == 201

    # Get the user ID from the response
    user_id = response.json()['id']

    # Send a GET request to retrieve the user details
    response = requests.get(f'https://api.example.com/users/{user_id}')
    assert response.status_code == 200
    assert response.json()['name'] == 'John Doe'
    assert response.json()['email'] == 'john@example.com'

    # Send a DELETE request to remove the user
    response = requests.delete(f'https://api.example.com/users/{user_id}')
    assert response.status_code == 204

Slide 11: End-to-End Testing

End-to-End (E2E) testing is a type of testing that simulates real-world scenarios and tests the entire application flow from start to finish, including external dependencies and integrations.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def test_login_flow():
    # Set up the webdriver
    driver = webdriver.Chrome()
    driver.get('https://example.com/login')

    # Enter login credentials
    username_field = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, 'username'))
    )
    username_field.send_keys('testuser')

    password_field = driver.find_element_by_id('password')
    password_field.send_keys('testpassword')

    # Submit the login form
    submit_button = driver.find_element_by_id('submit')
    submit_button.click()

    # Verify successful login
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, 'welcome-message'))
    )

    # Cleanup
    driver.quit()

Slide 12: Performance Testing

Performance testing is used to evaluate the speed, responsiveness, and stability of an application under different workloads and conditions.

import locust

class MyTaskSet(TaskSet):
    @task
    def my_task(self):
        response = self.client.get('/api/data')
        print(f'Response time: {response.elapsed.total_seconds() * 1000} ms')

class MyLoadTest(HttpLocust):
    task_set = MyTaskSet
    min_wait = 1000
    max_wait = 5000

Slide 13: Additional Resources

For further learning and exploration of Python clean testing practices, here are some recommended resources:

  • "Python Testing with pytest" by Brian Okken (Book)
  • "Test-Driven Development with Python" by Harry J.W. Percival (Book)
  • "Clean Code" by Robert C. Martin (Book)
  • "Python Testing" by Madhav Sangewar (Arxiv: https://arxiv.org/abs/2301.07285)

These resources cover various aspects of testing, including test-driven development, best practices, and advanced techniques for writing clean and maintainable tests in Python.