Task
Analyze the selected Python function or method and generate focused, production-quality unit tests using Python's built-in unittest framework.
Tests must be organized into classes that inherit from unittest.TestCase.
The goal is to validate the public behavior of the target while keeping tests isolated, deterministic, readable, and easy to maintain.
Testing Framework
Use exclusively:
import unittest
For mocks, patches, spies, and dependency isolation, use:
from unittest.mock import Mock, MagicMock, AsyncMock, patch, call
Do not use:
- pytest
- pytest fixtures
- pytest.mark
- monkeypatch
- nose
- third-party mocking libraries
- bare test functions
Every test must belong to a unittest.TestCase class.
Example:
import unittest
from unittest.mock import patch
from project.module import calculate_total
class TestCalculateTotal(unittest.TestCase):
def test_returns_total_for_valid_items(self):
result = calculate_total([
{"price": 10.0, "quantity": 2},
{"price": 5.0, "quantity": 1},
])
self.assertEqual(result, 25.0)
if __name__ == "__main__":
unittest.main()
Test Generation Strategy
1. Understand the Target
Before generating tests:
- Read the complete target function or method.
- Identify its inputs and outputs.
- Identify dependencies it calls.
- Identify possible exceptions.
- Identify state mutations or side effects.
- Identify branches and important conditions.
- Inspect surrounding code when necessary to understand expected behavior.
- Inspect existing tests to follow the project's conventions.
Do not invent behavior that is not supported by the implementation or surrounding project.
2. Core Functionality Tests
Test the primary expected behavior.
Include scenarios such as:
- typical valid input;
- realistic production-like input;
- expected return value;
- different meaningful branches;
- optional/default arguments when applicable.
Prefer realistic domain data over placeholder values such as "foo" or "bar".
3. Input Validation Tests
When relevant, test:
None;- empty strings;
- empty lists;
- empty dictionaries;
- invalid types;
- malformed values;
- zero;
- negative numbers;
- minimum values;
- maximum values;
- values immediately outside valid boundaries.
Only test validation that actually belongs to the target or its contract.
Do not create tests for hypothetical validation rules.
4. Error Handling Tests
Test exceptions explicitly.
Use the appropriate unittest assertions:
with self.assertRaises(ValueError):
target(...)
When the exception message is part of the contract:
with self.assertRaisesRegex(
ValueError,
"expected message",
):
target(...)
Validate:
- exception type;
- relevant error message;
- dependency failures;
- invalid state;
- important edge cases.
Do not catch exceptions manually unless necessary.
5. External Dependencies
Unit tests must not perform real external I/O.
Mock dependencies such as:
- HTTP requests;
- databases;
- filesystem access;
- AWS services;
- APIs;
- SDK clients;
- subprocesses;
- queues;
- email services;
- clocks/time when behavior depends on time;
- UUID/random generation when deterministic output is required.
Patch dependencies where they are looked up by the code under test, not necessarily where they were originally defined.
Example:
@patch("project.service.httpx.get")
def test_fetches_remote_resource(self, mock_get):
mock_get.return_value.json.return_value = {
"status": "authorized"
}
result = fetch_invoice("123")
mock_get.assert_called_once_with(
"https://example.com/invoices/123"
)
self.assertEqual(result["status"], "authorized")
Never make a real network request in a unit test.
6. Side Effects and Interactions
When the target produces side effects, verify them explicitly.
Examples:
mock_client.send.assert_called_once()
mock_repository.save.assert_called_once_with(expected)
self.assertEqual(instance.status, expected_status)
self.assertFalse(mock_client.delete.called)
Validate both:
- expected calls happen;
- forbidden/unexpected calls do not happen when relevant.
Use:
assert_called_once();assert_called_once_with(...);assert_not_called();assert_has_calls(...);call_args;call_args_list;
when appropriate.
7. Class Structure
Use descriptive test classes.
For a function:
class TestIssueInvoice(unittest.TestCase):
...
For a class method:
class TestInvoiceServiceIssueInvoice(unittest.TestCase):
...
If the target has several distinct behavioral areas, multiple test classes are allowed:
class TestIssueInvoiceSuccess(unittest.TestCase):
...
class TestIssueInvoiceValidation(unittest.TestCase):
...
class TestIssueInvoiceErrors(unittest.TestCase):
...
Prefer one cohesive class unless splitting materially improves readability.
8. Setup and Cleanup
Use setUp() when multiple tests require the same initialization:
class TestInvoiceService(unittest.TestCase):
def setUp(self):
self.client = MagicMock()
self.service = InvoiceService(client=self.client)
Use tearDown() only when cleanup is actually required.
Avoid putting assertions inside setUp() or tearDown().
Do not create large shared setup blocks for data used by only one test.
9. AAA Pattern
Every test must conceptually follow:
Arrange
Prepare input, dependencies, mocks, and expected values.
Act
Execute the target behavior.
Assert
Verify output, state, exceptions, and interactions.
Example:
def test_returns_authorized_invoice(self):
# Arrange
self.client.issue.return_value = {
"access_key": "123456789",
"status": "authorized",
}
# Act
result = self.service.issue_invoice(
client_name="Acme Ltd",
tax_id="12345678000199",
)
# Assert
self.assertEqual(result["status"], "authorized")
self.client.issue.assert_called_once()
Comments for Arrange, Act, and Assert are optional when the structure is already obvious.
Do not add comments that merely repeat the code.
10. Test Naming
Use descriptive snake_case names that explain behavior and scenario.
Good:
def test_returns_invoice_when_api_returns_authorized_status(self):
def test_raises_value_error_when_tax_id_is_empty(self):
def test_does_not_call_api_when_validation_fails(self):
def test_propagates_authentication_error_from_client(self):
Avoid vague names:
def test_success(self):
def test_error(self):
def test_case_1(self):
A developer should understand the regression being protected against from the test name alone.
11. Async Code
When the target is asynchronous, use:
class TestAsyncOperation(unittest.IsolatedAsyncioTestCase):
and:
async def test_returns_expected_result(self):
result = await target()
self.assertEqual(result, expected)
Use AsyncMock for asynchronous dependencies:
self.client.issue = AsyncMock(
return_value={"status": "authorized"}
)
Do not use asyncio.run() inside individual tests when IsolatedAsyncioTestCase is appropriate.
12. Parameter-Like Scenarios
Because unittest does not provide pytest-style parametrization, use subTest() for closely related cases:
def test_rejects_invalid_values(self):
invalid_values = [
None,
"",
-1,
]
for value in invalid_values:
with self.subTest(value=value):
with self.assertRaises(ValueError):
target(value)
Use subTest() only when the assertion and expected behavior are genuinely identical.
Create separate tests when scenarios represent different behaviors.
13. Private Methods
Prefer testing public behavior.
Do not test private implementation details such as:
_internal_method()
unless:
- the project explicitly tests private methods;
- the method contains independently significant behavior;
- there is no reasonable public interface through which to test it.
Avoid tests tightly coupled to implementation details that would fail after a harmless refactor.
14. Existing Project Patterns
Before creating the test file, inspect existing tests when available.
Follow existing conventions for:
- test directory;
- module naming;
- import style;
setUp;- mocks;
- factories;
- fixtures implemented with unittest;
- helper classes;
- test data;
- naming.
Prefer consistency with the repository over introducing a new test architecture.
However, generated tests must still use unittest.TestCase or unittest.IsolatedAsyncioTestCase.
15. Test Independence
Every test must be independently executable.
Tests must not:
- depend on execution order;
- depend on state produced by another test;
- reuse mutated global state;
- depend on real external services;
- depend on the current date/time unless explicitly controlled;
- leave patched objects active after execution.
Running:
python -m unittest
must produce deterministic results.
Coverage Priorities
Prioritize behavioral confidence over maximizing line coverage.
Generate tests in this order:
- successful primary behavior;
- meaningful alternate behavior;
- important validation;
- expected exception;
- external dependency failure;
- important side effect;
- boundary condition;
- regression-prone edge case.
Do not generate redundant tests solely to increase coverage.
Number of Tests
Generate approximately 5–8 focused test methods for a normal target.
Generate fewer when the function is trivial.
Generate more only when the target contains enough meaningful branches to justify them.
Do not manufacture scenarios simply to reach a test count.
Output Requirements
Generate a complete Python test module ready to save and execute.
The result must include:
import unittest
and all required project imports.
When mocks are required:
from unittest.mock import Mock, MagicMock, AsyncMock, patch, call
Import only the mock utilities actually used.
End standalone test modules with:
if __name__ == "__main__":
unittest.main()
The generated code must:
- be syntactically valid Python;
- use
unittest; - use classes;
- have deterministic tests;
- contain no real external I/O;
- follow existing project conventions where available;
- avoid unnecessary mocks;
- avoid testing implementation details;
- be ready to run without manual restructuring.
Final Instruction
Analyze the implementation before writing tests.
Generate the smallest high-value test suite that provides strong confidence in the target's behavior and catches realistic regressions.
Use Python unittest with class-based tests only.
Do not use pytest syntax or standalone test functions.