Python-Unit-Test-Generator mit pytest
Von Wikiprompt, der freien Prompt-Enzyklopädie
Python-Unit-Test-Generator mit pytest Ein strukturierter Systemprompt, der eine KI dazu anleitet, umfassende pytest-Unit-Tests mit Analyse, Abdeckungszuordnung, Mocking und Zusammenfassung zu generieren.
Prompt-InhaltSpeichern
🌐
"""
Unit test suite for the provided Python code.
This suite validates the functionality, edge cases, and error handling
of the code under test. It uses pytest as the testing framework and
unittest.mock for isolating external dependencies.
"""
import pytest
from unittest.mock import MagicMock, patch
# --- Paste the code to be tested here ---
# (Assuming the code is defined in this module or imported)
# For demonstration, let's assume the code is as follows:
# (Replace with actual code)
def calculate_discount(price, discount_percent):
"""Calculate discounted price."""
if price < 0:
raise ValueError("Price cannot be negative")
if discount_percent < 0 or discount_percent > 100:
raise ValueError("Discount must be between 0 and 100")
return price * (1 - discount_percent / 100)
def fetch_user_data(user_id):
"""Fetch user data from an external API."""
# Simulated external call
import requests
response = requests.get(f"https://api.example.com/users/{user_id}")
response.raise_for_status()
return response.json()
class ShoppingCart:
"""A simple shopping cart."""
def __init__(self):
self.items = []
def add_item(self, name, price, quantity=1):
"""Add an item to the cart."""
if quantity <= 0:
raise ValueError("Quantity must be positive")
if price < 0:
raise ValueError("Price cannot be negative")
self.items.append({"name": name, "price": price, "quantity": quantity})
def total(self):
"""Calculate total price."""
return sum(item["price"] * item["quantity"] for item in self.items)
# --- End of code to be tested ---
# =============================================================================
# STEP 1 - Code Analysis (Documented in comments below)
# =============================================================================
# Code Purpose: Provides utility functions (calculate_discount, fetch_user_data)
# and a ShoppingCart class for e-commerce operations.
# Functions/Classes:
# - calculate_discount(price, discount_percent)
# - fetch_user_data(user_id)
# - ShoppingCart.add_item(name, price, quantity)
# - ShoppingCart.total()
# Inputs:
# - calculate_discount: price (float/int), discount_percent (float/int)
# - fetch_user_data: user_id (int/str)
# - add_item: name (str), price (float/int), quantity (int)
# - total: none
# Outputs:
# - calculate_discount: float
# - fetch_user_data: dict
# - add_item: None (modifies state)
# - total: float
# Code Branches:
# - calculate_discount: if price < 0, if discount_percent out of range
# - fetch_user_data: external API call, raise_for_status
# - add_item: if quantity <= 0, if price < 0
# - total: sum over items
# External Deps:
# - fetch_user_data: requests.get (external API)
# Failure Points:
# - calculate_discount: invalid inputs
# - fetch_user_data: network errors, API errors
# - add_item: invalid quantity/price
# Risk Areas:
# - Boundary values for discount_percent (0, 100)
# - Empty cart for total()
# - Large quantities/values
# =============================================================================
# STEP 2 - Coverage Map
# =============================================================================
# | # | Function/Class | Test Scenario | Category | Priority |
# |---|----------------------|----------------------------------------|-------------------|------------|
# | 1 | calculate_discount | Valid discount calculation | Happy Path | Must Have |
# | 2 | calculate_discount | Zero discount | Edge Case | Must Have |
# | 3 | calculate_discount | 100% discount | Edge Case | Must Have |
# | 4 | calculate_discount | Negative price | Exception Test | Must Have |
# | 5 | calculate_discount | Discount out of range (negative) | Exception Test | Must Have |
# | 6 | calculate_discount | Discount out of range (>100) | Exception Test | Must Have |
# | 7 | calculate_discount | Float inputs | Edge Case | Should Have|
# | 8 | fetch_user_data | Successful API call | Happy Path | Must Have |
# | 9 | fetch_user_data | API returns 404 | Exception Test | Must Have |
# | 10| fetch_user_data | Network error | Mock/Patch Test | Must Have |
# | 11| ShoppingCart.add_item| Add single item | Happy Path | Must Have |
# | 12| ShoppingCart.add_item| Add multiple items | Happy Path | Should Have|
# | 13| ShoppingCart.add_item| Invalid quantity (zero) | Exception Test | Must Have |
# | 14| ShoppingCart.add_item| Invalid quantity (negative) | Exception Test | Must Have |
# | 15| ShoppingCart.add_item| Invalid price (negative) | Exception Test | Must Have |
# | 16| ShoppingCart.total | Empty cart | Edge Case | Must Have |
# | 17| ShoppingCart.total | Cart with items | Happy Path | Must Have |
# | 18| ShoppingCart.total | Cart with multiple quantities | Edge Case | Should Have|
# Total Planned Tests: 18
# Estimated Coverage: 95%+ (Line & Branch)
# =============================================================================
# STEP 3 - Generated Test Suite
# =============================================================================
class TestCalculateDiscount:
"""Tests for calculate_discount function."""
def test_calculate_discount_valid_discount_returns_discounted_price(self):
"""Test that a valid discount returns the correct price."""
# Arrange
price = 100.0
discount = 20.0
expected = 80.0
# Act
result = calculate_discount(price, discount)
# Assert
assert result == pytest.approx(expected)
def test_calculate_discount_zero_discount_returns_original_price(self):
"""Test that a zero discount returns the original price."""
# Arrange
price = 50.0
discount = 0.0
# Act
result = calculate_discount(price, discount)
# Assert
assert result == price
def test_calculate_discount_full_discount_returns_zero(self):
"""Test that a 100% discount returns zero."""
# Arrange
price = 75.0
discount = 100.0
# Act
result = calculate_discount(price, discount)
# Assert
assert result == 0.0
def test_calculate_discount_negative_price_raises_value_error(self):
"""Test that a negative price raises ValueError."""
# Arrange
price = -10.0
discount = 10.0
# Act & Assert
with pytest.raises(ValueError, match="Price cannot be negative"):
calculate_discount(price, discount)
def test_calculate_discount_negative_discount_raises_value_error(self):
"""Test that a negative discount raises ValueError."""
# Arrange
price = 100.0
discount = -5.0
# Act & Assert
with pytest.raises(ValueError, match="Discount must be between 0 and 100"):
calculate_discount(price, discount)
def test_calculate_discount_discount_over_100_raises_value_error(self):
"""Test that a discount over 100 raises ValueError."""
# Arrange
price = 100.0
discount = 150.0
# Act & Assert
with pytest.raises(ValueError, match="Discount must be between 0 and 100"):
calculate_discount(price, discount)
@pytest.mark.parametrize("price, discount, expected", [
(99.99, 10.5, 89.4905),
(0.01, 99.99, 0.0001),
(1234.56, 33.33, 823.123152),
])
def test_calculate_discount_float_inputs_returns_correct_result(self, price, discount, expected):
"""Test that float inputs are handled correctly."""
# Act
result = calculate_discount(price, discount)
# Assert
assert result == pytest.approx(expected)
class TestFetchUserData:
"""Tests for fetch_user_data function."""
@patch("requests.get")
def test_fetch_user_data_successful_call_returns_user_data(self, mock_get):
"""Test that a successful API call returns user data."""
# Arrange
mock_response = MagicMock()
mock_response.json.return_value = {"id": 1, "name": "John Doe"}
mock_response.raise_for_status.return_value = None
mock_get.return_value = mock_response
# Act
result = fetch_user_data(1)
# Assert
assert result == {"id": 1, "name": "John Doe"}
mock_get.assert_called_once_with("https://api.example.com/users/1")
mock_response.raise_for_status.assert_called_once()
@patch("requests.get")
def test_fetch_user_data_api_404_raises_exception(self, mock_get):
"""Test that a 404 response raises an exception."""
# Arrange
mock_response = MagicMock()
mock_response.raise_for_status.side_effect = Exception("404 Not Found")
mock_get.return_value = mock_response
# Act & Assert
with pytest.raises(Exception, match="404 Not Found"):
fetch_user_data(999)
@patch("requests.get")
def test_fetch_user_data_network_error_raises_exception(self, mock_get):
"""Test that a network error raises an exception."""
# Arrange
mock_get.side_effect = ConnectionError("Network unreachable")
# Act & Assert
with pytest.raises(ConnectionError, match="Network unreachable"):
fetch_user_data(1)
class TestShoppingCart:
"""Tests for ShoppingCart class."""
@pytest.fixture
def cart(self):
"""Create a fresh ShoppingCart instance."""
return ShoppingCart()
def test_add_item_single_item_adds_to_cart(self, cart):
"""Test that adding a single item works correctly."""
# Act
cart.add_item("Apple", 0.99)
# Assert
assert len(cart.items) == 1
assert cart.items[0] == {"name": "Apple", "price": 0.99, "quantity": 1}
def test_add_item_multiple_items_adds_all_to_cart(self, cart):
"""Test that adding multiple items works correctly."""
# Act
cart.add_item("Apple", 0.99)
cart.add_item("Banana", 1.29, quantity=3)
# Assert
assert len(cart.items) == 2
assert cart.items[0]["name"] == "Apple"
assert cart.items[1]["quantity"] == 3
def test_add_item_zero_quantity_raises_value_error(self, cart):
"""Test that a zero quantity raises ValueError."""
# Act & Assert
with pytest.raises(ValueError, match="Quantity must be positive"):
cart.add_item("Apple", 0.99, quantity=0)
def test_add_item_negative_quantity_raises_value_error(self, cart):
"""Test that a negative quantity raises ValueError."""
# Act & Assert
with pytest.raises(ValueError, match="Quantity must be positive"):
cart.add_item("Apple", 0.99, quantity=-1)
def test_add_item_negative_price_raises_value_error(self, cart):
"""Test that a negative price raises ValueError."""
# Act & Assert
with pytest.raises(ValueError, match="Price cannot be negative"):
cart.add_item("Apple", -0.99)
def test_total_empty_cart_returns_zero(self, cart):
"""Test that an empty cart has a total of zero."""
# Act
result = cart.total()
# Assert
assert result == 0.0
def test_total_cart_with_items_returns_sum(self, cart):
"""Test that the total is correctly calculated with items."""
# Arrange
cart.add_item("Apple", 0.99)
cart.add_item("Banana", 1.29, quantity=2)
# Act
result = cart.total()
# Assert
assert result == pytest.approx(0.99 + 1.29 * 2)
def test_total_cart_with_multiple_quantities_returns_correct_sum(self, cart):
"""Test that the total handles multiple quantities correctly."""
# Arrange
cart.add_item("Apple", 0.50, quantity=3)
cart.add_item("Orange", 0.75, quantity=2)
# Act
result = cart.total()
# Assert
assert result == pytest.approx(0.50 * 3 + 0.75 * 2)
# =============================================================================
# STEP 4 - Mock & Patch Setup
# =============================================================================
# | # | Dependency | Mock Strategy | Patch Target | What's Being Isolated |
# |---|-----------|---------------|--------------|----------------------|
# | 1 | requests.get | MagicMock with configured return/side_effect | requests.get | External API call |
#
# Complete mock/fixture setup:
# The mock for requests.get is set up inline in each test using @patch decorator.
# This isolates the test from actual network calls.
#
# Why mocked: To avoid real network calls, ensure deterministic tests, and
# test error handling without external dependencies.
#
# Example usage in test_fetch_user_data_successful_call_returns_user_data:
# The mock_get is configured to return a MagicMock with a json() method
# that returns the expected user data. This isolates the test from the
# actual API.
# =============================================================================
# STEP 5 - Test Summary Card
# =============================================================================
# Test Suite Overview:
# Total Tests Generated: 18
# Estimated Coverage: 95% (Line) | 90% (Branch)
# Framework Used: pytest + unittest.mock
#
# | Category | Count | Notes |
# |-------------------|-------|------------------------------------|
# | Happy Path | 6 | Core functionality tests |
# | Edge Cases | 5 | Boundary and special values |
# | Exception Tests | 5 | Error handling validation |
# | Mock/Patch | 3 | External dependency isolation |
# | Negative Inputs | 4 | Invalid input validation |
# | Must Have | 12 | Critical functionality |
# | Should Have | 4 | Important edge cases |
# | Nice to Have | 2 | Additional coverage |
#
# | Quality Marker | Status | Notes |
# |-------------------------|---------|------------------------------|
# | AAA Pattern | Yes | All tests follow AAA |
# | Naming Convention | Yes | Consistent naming scheme |
# | Fixtures Used | Yes | cart fixture for ShoppingCart|
# | Parametrize Used | Yes | For float input tests |
# | Mocks Properly Isolated | Yes | Only external deps mocked |
# | Deterministic Tests | Yes | No randomness or external state |
# | PEP8 Compliant | Yes | Follows PEP8 guidelines |
# | Docstrings Present | Yes | All tests have docstrings |
#
# Gaps & Recommendations:
# - Property-based testing could be added for calculate_discount
# - Integration tests for fetch_user_data with a real test server
# - Fuzzing for ShoppingCart.add_item with random inputs
# - Command to run: pytest test_suite.py -v --tb=short
Melde dich an, um den vollständigen Prompt zu sehen
Weiter mit:
Mit der Anmeldung akzeptierst du unsere Nutzungsbedingungen und Datenschutz
Verwendung
Dieser Prompt ist für die Verwendung mit coding gedacht. Kopiere den Inhalt oben und füge ihn in dein bevorzugtes KI-Tool ein.
Für beste Ergebnisse passe die Platzhalter (eckige Klammern oder Großbuchstaben) an deine Anforderungen an.
Diskussion
0 Kommentare