Introduction
Testing is the backbone of reliable software. Yet, many developers skip writing tests because they find them tedious or time-consuming. With AI-assisted prompting, you can generate robust unit and integration tests in seconds. This article provides 10 battle-tested prompts for Python's pytest, JavaScript's Jest, and Python's unittest frameworks. Each prompt is designed to be copied directly into your AI tool (like ChatGPT, Claude, or GitHub Copilot) and adapted to your codebase. Based on official documentation and real-world usage, these prompts cover edge cases, mocking, fixtures, and async testing — saving you hours of manual work.
Prompt 1: Generate Basic Unit Tests for a Function
Prompt: "Write unit tests for the following function using pytest. Include tests for normal inputs, edge cases (empty list, None, negative numbers), and expected exceptions. Use parametrize for multiple scenarios."
Example:
# Function to test
def calculate_average(numbers):
if not numbers:
raise ValueError("List cannot be empty")
return sum(numbers) / len(numbers)
Generated test code:
import pytest
from my_module import calculate_average
@pytest.mark.parametrize("numbers, expected", [
([1, 2, 3], 2.0),
([0, 0, 0], 0.0),
([1.5, 2.5], 2.0),
])
def test_calculate_average_valid(numbers, expected):
assert calculate_average(numbers) == expected
def test_calculate_average_empty():
with pytest.raises(ValueError, match="cannot be empty"):
calculate_average([])
Why it works: This prompt ensures comprehensive coverage by explicitly asking for parametrization and exception testing. It follows the best practice of testing one behavior per test case (see pytest docs).
Prompt 2: Mock External API Calls in Integration Tests
Prompt: "Write an integration test for a function that calls an external REST API. Use mocking to simulate HTTP responses. Test both success (200) and failure (404, 500) scenarios using pytest with responses library or unittest.mock."
Example:
import requests
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
response.raise_for_status()
return response.json()
Generated test code:
import pytest
from unittest.mock import patch
from my_module import get_user_data
@patch("my_module.requests.get")
def test_get_user_data_success(mock_get):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"}
result = get_user_data(1)
assert result["name"] == "Alice"
@patch("my_module.requests.get")
def test_get_user_data_404(mock_get):
mock_get.return_value.status_code = 404
mock_get.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError
with pytest.raises(requests.exceptions.HTTPError):
get_user_data(999)
Why it works: Mocking external APIs makes tests fast and deterministic. The prompt specifies status codes and uses side_effect for exceptions (technique from Real Python mocking guide).
Prompt 3: Test Async Functions with pytest-asyncio
Prompt: "Write async unit tests for the following coroutine using pytest-asyncio. Test successful completion and exception propagation. Use fixtures for async setup."
Example:
async def fetch_data(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
Generated test code:
import pytest
from unittest.mock import AsyncMock
from my_module import fetch_data
@pytest.mark.asyncio
async def test_fetch_data_success():
mock_session = AsyncMock()
mock_response = AsyncMock()
mock_response.json.return_value = {"key": "value"}
mock_session.get.return_value.__aenter__.return_value = mock_response
with patch("my_module.aiohttp.ClientSession", return_value=mock_session):
result = await fetch_data("http://test.com")
assert result["key"] == "value"
Why it works: Async testing requires special setup. This prompt leverages pytest-asyncio (official plugin documented in pytest-asyncio docs) and AsyncMock for mocking coroutines.
Prompt 4: Generate Jest Tests for React Components
Prompt: "Write Jest unit tests for the following React component using @testing-library/react. Test rendering with props, user interaction (click, input), and snapshot testing. Include cleanup in afterEach."
Example:
function Counter({ initialCount = 0 }) {
const [count, setCount] = React.useState(initialCount);
return (
<div>
<p data-testid="count">{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Generated test code:
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import Counter from './Counter';
afterEach(cleanup);
test('renders initial count', () => {
render(<Counter initialCount={5} />);
expect(screen.getByTestId('count')).toHaveTextContent('5');
});
test('increments count on button click', () => {
render(<Counter />);
fireEvent.click(screen.getByText('Increment'));
expect(screen.getByTestId('count')).toHaveTextContent('1');
});
Why it works: This prompt covers the core patterns from Testing Library docs. It asks for user interaction and snapshot testing, which catches UI regressions.
Prompt 5: Test Database Operations with Fixtures
Prompt: "Write pytest integration tests for database CRUD operations using fixtures to set up and tear down a test database (SQLite in-memory). Test create, read, update, and delete with parametrization."
Example:
import sqlite3
def add_user(conn, name):
conn.execute("INSERT INTO users (name) VALUES (?)", (name,))
conn.commit()
def get_user(conn, user_id):
return conn.execute("SELECT * FROM users WHERE id = ?", (user_id,)).fetchone()
Generated test code:
import pytest
@pytest.fixture
def db_conn():
conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
yield conn
conn.close()
@pytest.mark.parametrize("name", ["Alice", "Bob", ""])
def test_add_and_get_user(db_conn, name):
add_user(db_conn, name)
user = get_user(db_conn, 1)
assert user[1] == name
Why it works: Using in-memory SQLite ensures tests are isolated and fast. The fixture pattern is recommended in pytest fixtures docs.
Prompt 6: Test File I/O Operations
Prompt: "Write unit tests for a function that reads/writes files. Use pytest's tmp_path fixture to create temporary files. Test file creation, reading content, and handling of missing files."
Example:
def save_config(config, path):
with open(path, "w") as f:
f.write(config)
def load_config(path):
if not os.path.exists(path):
return None
with open(path, "r") as f:
return f.read()
Generated test code:
import pytest
def test_save_and_load_config(tmp_path):
d = tmp_path / "sub"
d.mkdir()
p = d / "config.txt"
save_config("key=value", p)
assert load_config(p) == "key=value"
def test_load_missing_file(tmp_path):
p = tmp_path / "missing.txt"
assert load_config(p) is None
Why it works: tmp_path is a built-in pytest fixture that provides unique temporary directories and handles cleanup (see pytest tmp_path docs).
Prompt 7: Generate Unittest Test Cases for a Class
Prompt: "Write unittest test cases for the following class. Use setUp and tearDown methods. Test all public methods with edge cases. Include test for class attributes and state changes."
Example:
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Amount must be positive")
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
Generated test code:
import unittest
from my_module import BankAccount
class TestBankAccount(unittest.TestCase):
def setUp(self):
self.account = BankAccount(100)
def test_initial_balance(self):
self.assertEqual(self.account.balance, 100)
def test_deposit(self):
self.account.deposit(50)
self.assertEqual(self.account.balance, 150)
def test_deposit_negative(self):
with self.assertRaises(ValueError):
self.account.deposit(-10)
def test_withdraw_insufficient(self):
with self.assertRaises(ValueError):
self.account.withdraw(200)
if __name__ == '__main__':
unittest.main()
Why it works: This prompt follows the classic unittest pattern from Python docs. It explicitly asks for setUp/tearDown and edge cases.
Prompt 8: Test Error Handling and Logging
Prompt: "Write tests for error handling and logging in the following function. Use pytest's caplog fixture to capture log messages. Test that correct log levels and messages are emitted on errors."
Example:
import logging
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
logging.error("Division by zero attempted")
raise
Generated test code:
import pytest
import logging
def test_divide_logs_error(caplog):
caplog.set_level(logging.ERROR)
with pytest.raises(ZeroDivisionError):
divide(10, 0)
assert "Division by zero attempted" in caplog.text
Why it works: caplog is a built-in pytest fixture for testing logs (documented in pytest logging docs). The prompt ensures log assertions without external mocking.
Prompt 9: Test Configuration and Environment Variables
Prompt: "Write tests for a function that reads configuration from environment variables. Use pytest's monkeypatch fixture to set env vars. Test default values and overrides."
Example:
import os
def get_db_url():
return os.getenv("DATABASE_URL", "sqlite:///default.db")
Generated test code:
import pytest
def test_get_db_url_default(monkeypatch):
monkeypatch.delenv("DATABASE_URL", raising=False)
assert get_db_url() == "sqlite:///default.db"
def test_get_db_url_custom(monkeypatch):
monkeypatch.setenv("DATABASE_URL", "postgres://user:pass@localhost/db")
assert get_db_url() == "postgres://user:pass@localhost/db"
Why it works: monkeypatch is a pytest fixture for safely modifying environment variables (see pytest monkeypatch docs).
Prompt 10: Test API Routes with FastAPI TestClient
Prompt: "Write integration tests for FastAPI endpoints using TestClient. Test GET, POST, and error responses. Use fixtures for database session and override dependencies."
Example:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return {"id": 1, **item.dict()}
Generated test code:
from fastapi.testclient import TestClient
from my_app import app
client = TestClient(app)
def test_create_item():
response = client.post("/items/", json={"name": "Laptop", "price": 999.99})
assert response.status_code == 200
assert response.json()["name"] == "Laptop"
def test_create_item_invalid():
response = client.post("/items/", json={"name": ""})
assert response.status_code == 422
Why it works: FastAPI's TestClient is based on Starlette's test client and is the recommended way to test endpoints (see FastAPI testing docs). The prompt covers both success and validation error scenarios.
Conclusion
These 10 prompts cover the most common testing scenarios across Python and JavaScript ecosystems — from mocking and fixtures to async tests and error handling. By integrating them into your daily workflow, you can generate comprehensive test suites in minutes. Start by copying the prompt that matches your current task, adapt the function names, and watch your test coverage grow. For deeper dives, refer to the official documentation links provided for each framework. Happy testing!
Comments