Loading...
Loading...
Generates pytest test suites with happy path, edge cases, error conditions, fixture scaffolding, mocks, async patterns. Triggers on: "generate tests", "write tests for", "test this function", "create test suite", "pytest for", "unit tests for", "mock strategy for".
npx skill4agent add mathews-tom/armory test-harness| File | Contents | Load When |
|---|---|---|
| Fixture scopes, parametrize, marks, conftest layout, built-in fixtures | Always |
| Mock decision tree, patch boundaries, assertions, anti-patterns | Target has external dependencies |
| pytest-asyncio modes, event loop fixtures, async mocking | Target contains async code |
| Factory fixtures, yield teardown, scope selection, composition | Test requires non-trivial setup |
| Threshold table, branch vs line, pytest-cov config, exclusion patterns | Coverage assessment requested |
mockerunittest.mockgit diff --name-only HEAD~5| Category | What to Test | Example |
|---|---|---|
| Happy path | Expected inputs produce expected outputs | |
| Boundary | Edge values at limits of valid input | Empty string, zero, max int, single element |
| Error | Invalid inputs trigger proper exceptions | |
| State | State transitions produce correct side effects | Object moves from |
| Scope | Use When | Example |
|---|---|---|
| Default. Each test gets fresh state | Most unit tests |
| Tests within a class share expensive setup | DB connection per test class |
| All tests in a file share setup | Loaded config file |
| Entire test run shares setup | Docker container startup |
yieldconftest.pydatetime.nowtime.sleep@patch('mymodule.requests.get')@patch('requests.get')# tests/test_{module}.py
import pytest
from unittest.mock import Mock, patch, MagicMock
from {module} import {target_function, TargetClass}
# ============================================================
# Fixtures
# ============================================================
@pytest.fixture
def valid_input():
"""Standard valid input for happy path tests."""
return {concrete values}
@pytest.fixture
def mock_database():
"""Mock database connection."""
with patch("{module}.db_connection") as mock_db:
mock_db.query.return_value = [{expected data}]
yield mock_db
# ============================================================
# {target_function} Tests
# ============================================================
class TestTargetFunction:
"""Tests for {target_function}."""
def test_happy_path(self, valid_input):
"""Returns expected result for valid input."""
result = target_function(valid_input)
assert result == {expected}
@pytest.mark.parametrize(
"input_val, expected",
[
({boundary_1}, {expected_1}),
({boundary_2}, {expected_2}),
({boundary_3}, {expected_3}),
],
ids=["empty", "single", "maximum"],
)
def test_boundary_conditions(self, input_val, expected):
"""Handles boundary inputs correctly."""
assert target_function(input_val) == expected
def test_invalid_input_raises(self):
"""Raises TypeError for invalid input."""
with pytest.raises(TypeError, match="expected str"):
target_function(None)
def test_external_call(self, mock_database):
"""Calls database with correct query."""
target_function("lookup_key")
mock_database.query.assert_called_once_with("SELECT * FROM t WHERE key = %s", ("lookup_key",))| Mode | Scope | Depth | When to Use |
|---|---|---|---|
| Single function | Happy path + 1 error case | Rapid iteration, TDD red-green cycle |
| File or class | Happy + boundary + error + mocks | Default for most requests |
| Module or package | All categories + async + parametrized matrix | Pre-release, critical path code |
"alice@example.com""test_email"42"some_number"@pytest.mark.parametrizeidsconftest.py| Problem | Resolution |
|---|---|
| Target function has no type hints | Infer types from usage patterns, default values, and docstrings. Note uncertainty in test docstring. |
| Target has deeply nested dependencies | Mock at the nearest boundary to the function under test. Do not mock transitive dependencies individually. |
| No existing test infrastructure (no conftest, no pytest config) | Generate a minimal |
| Target code is untestable (global state, hidden dependencies) | Flag the design issue in the output. Generate tests for what is testable. Suggest refactoring to improve testability. |
| Async code detected but pytest-asyncio not installed | Note the dependency requirement. Generate async test stubs with |
| Target module cannot be imported | Report the import error. Do not generate tests for unimportable code. |
| Rationalization | Reality |
|---|---|
| "Manual testing is sufficient" | Manual testing doesn't run in CI, doesn't catch regressions, and doesn't scale with the codebase |
| "This code is too simple to test" | Simple code becomes complex code — tests document expected behavior and catch regressions from future changes |
| "I'll add tests later" | Tests are specifications; without them, code behavior is undefined and later never comes |
| "Mocking everything makes the test fast" | Over-mocked tests pass when the real system fails — mock at boundaries, not deep in the call chain |
| "100% coverage means the code is correct" | Coverage measures execution, not correctness — a test that runs code without meaningful assertions adds no value |
| "The happy path test is enough" | Edge cases and error paths cause most production incidents — happy-path-only testing is false confidence |
test_<unit>_<scenario>_<expected_outcome>pytestnpm test