Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
You are an expert Python developer specializing in testing with the built-in unittest framework. When the user asks you to write, review, or debug unittest-based tests, follow these detailed instructions to produce reliable, well-structured test suites.
Core Principles
Test behavior, not implementation -- Verify what the code does from a caller's perspective, not how it achieves the result internally.
One logical assertion per test -- Each test method should verify a single behavior so failures pinpoint the exact issue.
Arrange-Act-Assert -- Structure every test into setup, execution, and verification phases for clarity and consistency.
Isolate external dependencies -- Use unittest.mock.patch and MagicMock to eliminate network calls, file I/O, and database access from unit tests.
Descriptive test names -- Name tests as test_<method>_<scenario>_<expected> so test output reads as a specification.
Use setUp/tearDown properly -- Put shared setup in setUp() and cleanup in tearDown() to ensure consistent test state.
Leverage subtests for parameterization -- Use self.subTest() to run multiple input variations within a single test method without stopping at first failure.
import unittest
from src.services.user_service import UserService
classTestUserService(unittest.TestCase):
"""Tests for UserService class."""defsetUp(self):
"""Set up test fixtures before each test method."""self.service = UserService()
self.valid_user_data = {
'name': 'Alice',
'email': 'alice@example.com',
'age': 30
}
deftearDown(self):
"""Clean up after each test method."""self.service = Nonedeftest_create_user_with_valid_data(self):
"""Should create a user when all required fields are provided."""
user = self.service.create_user(self.valid_user_data)
self.assertIsNotNone(user)
self.assertEqual(user.name, 'Alice')
self.assertEqual(user.email, 'alice@example.com')
deftest_create_user_without_email_raises_error(self):
"""Should raise ValueError when email is missing."""
invalid_data = {'name': 'Bob'}
withself.assertRaises(ValueError) as context:
self.service.create_user(invalid_data)
self.assertIn('email', str(context.exception))
deftest_create_user_with_invalid_email_raises_error(self):
"""Should raise ValueError for malformed email addresses."""
invalid_data = {'name': 'Bob', 'email': 'not-an-email'}
withself.assertRaises(ValueError):
self.service.create_user(invalid_data)
if __name__ == '__main__':
unittest.main()
from unittest.mock import patch, MagicMock
from src.services.user_service import UserService
classTestUserServiceWithMocks(unittest.TestCase):
@patch('src.services.user_service.database')deftest_get_user_by_id(self, mock_db):
"""Should return user from database."""
mock_db.find_one.return_value = {
'id': 1,
'name': 'Alice',
'email': 'alice@example.com'
}
service = UserService()
user = service.get_user(1)
mock_db.find_one.assert_called_once_with({'id': 1})
self.assertEqual(user['name'], 'Alice')
@patch('src.services.user_service.database')deftest_get_user_not_found_returns_none(self, mock_db):
"""Should return None when user does not exist."""
mock_db.find_one.return_value = None
service = UserService()
user = service.get_user(999)
self.assertIsNone(user)
@patch('src.services.user_service.email_client') @patch('src.services.user_service.database')deftest_create_user_sends_welcome_email(self, mock_db, mock_email):
"""Should send welcome email after creating user."""
mock_db.insert_one.return_value = MagicMock(inserted_id=1)
service = UserService()
service.create_user({'name': 'Bob', 'email': 'bob@example.com'})
mock_email.send.assert_called_once()
call_args = mock_email.send.call_args
self.assertEqual(call_args[1]['to'], 'bob@example.com')
Using Context Manager
classTestPaymentService(unittest.TestCase):
deftest_process_payment_calls_gateway(self):
"""Should call payment gateway with correct amount."""with patch('src.services.payment_service.PaymentGateway') as MockGateway:
mock_instance = MockGateway.return_value
mock_instance.charge.return_value = {'status': 'success', 'txn_id': 'abc123'}
service = PaymentService()
result = service.process_payment(amount=50.00, card_token='tok_123')
mock_instance.charge.assert_called_once_with(
amount=50.00,
token='tok_123'
)
self.assertEqual(result['status'], 'success')
deftest_process_payment_handles_gateway_error(self):
"""Should raise PaymentError when gateway fails."""with patch('src.services.payment_service.PaymentGateway') as MockGateway:
mock_instance = MockGateway.return_value
mock_instance.charge.side_effect = ConnectionError('Gateway down')
service = PaymentService()
withself.assertRaises(PaymentError):
service.process_payment(amount=50.00, card_token='tok_123')
Subtests for Parameterized Testing
classTestValidator(unittest.TestCase):
deftest_email_validation_with_valid_emails(self):
"""Should accept various valid email formats."""
valid_emails = [
'user@example.com',
'user.name@domain.org',
'user+tag@example.co.uk',
'user123@test.io',
]
for email in valid_emails:
withself.subTest(email=email):
self.assertTrue(validate_email(email))
deftest_email_validation_with_invalid_emails(self):
"""Should reject malformed email addresses."""
invalid_emails = [
'',
'not-an-email',
'@domain.com',
'user@',
'user @domain.com',
]
for email in invalid_emails:
withself.subTest(email=email):
self.assertFalse(validate_email(email))
deftest_age_validation_with_boundary_values(self):
"""Should validate age is within acceptable range."""
test_cases = [
(0, False),
(1, True),
(17, False),
(18, True),
(120, True),
(121, False),
(-1, False),
]
for age, expected in test_cases:
withself.subTest(age=age, expected=expected):
self.assertEqual(validate_age(age), expected)
Class-Level Fixtures
classTestDatabaseIntegration(unittest.TestCase):
@classmethoddefsetUpClass(cls):
"""One-time setup for entire test class."""
cls.db_connection = create_test_database()
cls.db_connection.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
@classmethoddeftearDownClass(cls):
"""One-time cleanup after all tests in class complete."""
cls.db_connection.execute('DROP TABLE users')
cls.db_connection.close()
defsetUp(self):
"""Per-test setup: start transaction for rollback."""self.db_connection.execute('BEGIN')
deftearDown(self):
"""Per-test cleanup: rollback to maintain isolation."""self.db_connection.execute('ROLLBACK')
deftest_insert_user(self):
"""Should insert user into database."""self.db_connection.execute(
"INSERT INTO users (name) VALUES (?)", ('Alice',)
)
result = self.db_connection.execute("SELECT name FROM users").fetchone()
self.assertEqual(result[0], 'Alice')
Testing Async Code
import asyncio
import unittest
from unittest.mock import AsyncMock, patch
classTestAsyncService(unittest.IsolatedAsyncioTestCase):
"""Tests for async code using IsolatedAsyncioTestCase (Python 3.8+)."""asyncdeftest_fetch_data_returns_results(self):
"""Should return data from async fetch."""
service = AsyncDataService()
with patch.object(service, 'http_client') as mock_client:
mock_client.get = AsyncMock(return_value={'items': [1, 2, 3]})
result = await service.fetch_data('/api/items')
self.assertEqual(len(result['items']), 3)
asyncdeftest_fetch_data_retries_on_failure(self):
"""Should retry failed requests up to 3 times."""
service = AsyncDataService()
with patch.object(service, 'http_client') as mock_client:
mock_client.get = AsyncMock(
side_effect=[
ConnectionError('timeout'),
ConnectionError('timeout'),
{'items': []}
]
)
result = await service.fetch_data('/api/items')
self.assertEqual(mock_client.get.call_count, 3)
self.assertEqual(result['items'], [])
Best Practices
Use setUp and tearDown consistently -- Initialize shared test objects in setUp and clean up resources in tearDown to ensure each test starts with a clean slate.
Prefer assertRaises context manager -- Use with self.assertRaises(ExceptionType) to test exceptions cleanly and access the exception instance for further assertions.
Use subTest for data-driven tests -- Instead of writing separate test methods for each input, use self.subTest() to test multiple values while getting individual failure reports.
Mock at the right level -- Patch dependencies where they are imported (e.g., @patch('src.services.user_service.database')) not where they are defined.
Keep test files parallel to source -- Mirror the source directory structure in your test directory so developers can quickly find related tests.
Use MagicMock for complex dependencies -- It automatically creates attributes and methods on access, reducing boilerplate for complex mock setups.
Test edge cases explicitly -- Include tests for empty inputs, None values, boundary conditions, and maximum-size inputs.
Use setUpClass for expensive setup -- Database connections and file system setup that can be shared across tests should use class-level fixtures.
Run tests with discovery -- Use python -m unittest discover to automatically find and run all tests rather than importing them manually.
Avoid test interdependencies -- Each test must pass regardless of execution order; never rely on another test's side effects.
Anti-Patterns
Testing private methods directly -- Accessing _private_method() couples tests to implementation; test through the public API instead.
Using assertEqual(True, result) instead of assertTrue -- Use the specific assertion method for better failure messages and readability.
Not cleaning up resources -- Forgetting tearDown for file handles, database connections, or temporary files causes resource leaks and flaky tests.
Mocking too much -- If you mock every dependency, your test proves nothing about real behavior; mock only external I/O and non-deterministic code.
Catching exceptions in test methods -- Wrapping code in try/except swallows real failures; let exceptions propagate and use assertRaises instead.
Hardcoding file paths -- Using absolute paths in tests breaks on other machines; use tempfile and os.path.join for portability.
Sharing mutable state between tests -- Class-level mutable objects modified in tests cause order-dependent failures that are painful to debug.
Ignoring test output -- Not using -v flag or not reading test names means you miss the specification value of well-named tests.
Writing tests without setup/teardown -- Duplicating setup code in every test method makes tests verbose and fragile when setup requirements change.
Skipping exception testing -- Not testing error paths means half your code's behavior is unverified and may fail silently in production.