{"name":"write-python-tests-with-pytest","description":"Writes clear, fast Python tests with pytest - arrange-act-assert structure, fixtures in conftest.py, parametrize for many cases, mocking only at the edges, and coverage reports. Use when the user wants to add Python tests, set up pytest, test a function or API, or fix flaky or slow Python tests.","category":"debugging","tags":["python","testing"],"models":["any"],"proven":false,"passing_families":0,"model_testing":"Not yet model-tested; testing Jan 2027","url":"https://theskillvault.ai/skills/write-python-tests-with-pytest","api_url":"https://theskillvault.ai/api/skills/write-python-tests-with-pytest","raw_url":"https://theskillvault.ai/api/skills/write-python-tests-with-pytest/raw","body":"# Write Python tests with pytest\n\npytest finds files named `test_*.py` and runs every function that starts with `test_`. Plain `assert` is all you need.\n\n## When to use\n- Your Python code has no tests and you want a safety net.\n- You need to test a FastAPI, Flask or Django endpoint.\n- Tests are flaky, slow or hard to read.\n\n## When not to use\n- You want to write the test before the code as a habit. Use test-first-with-tdd, then come back for pytest details.\n\n## Steps\n1. Install: `pip install pytest pytest-cov` (add `pytest-asyncio` for async code).\n2. Make a `tests/` folder that mirrors your package, with a `conftest.py` for shared fixtures.\n3. Write each test as arrange, act, assert. One behaviour per test, named for it: `test_refund_fails_when_order_is_shipped`.\n4. Use fixtures for setup you repeat, such as a test database or client. Keep their scope as small as works.\n5. Use `@pytest.mark.parametrize` to run one test over many inputs.\n6. Check errors with `with pytest.raises(ValueError):`.\n7. Mock only at the edges: network calls, time, payment providers. Use `monkeypatch` or `unittest.mock`.\n8. Run `pytest -q`, then `pytest --cov=yourpackage --cov-report=term-missing` to see untested lines.\n9. Add the test command to CI.\n\n```python\nimport pytest\nfrom shop.pricing import apply_discount\n\n@pytest.mark.parametrize(\"price, code, expected\", [(100, \"TEN\", 90), (100, None, 100)])\ndef test_apply_discount(price, code, expected):\n    assert apply_discount(price, code) == expected\n```\n\n## Gotchas\n- Tests that share state leak into each other. Use fixtures, not module-level globals.\n- Never point tests at a production database or real API keys. Use a test database and fake credentials.\n- Over-mocking tests your mocks, not your code. Prefer real objects inside your own code.\n- Use `tmp_path` for files, not real folders.\n\n## Portability\nWorks with any Python project and framework. If you use unittest today, pytest runs those tests too, so you can switch gradually instead of rewriting.\n\n## Example prompt\n\"Add pytest tests for my pricing module, including edge cases, and show me the coverage.\"\n\n## Done when\n- `pytest` passes locally and in CI.\n- Each important behaviour and error path has a named test.\n- No test touches real services, real money or real secrets.\n\n---\nAdapted from \"python-testing-patterns\" in wshobson/agents (MIT, Copyright (c) 2024 Seth Hobson). See LICENSE.txt.","files":["LICENSE.txt"],"license":"MIT","license_name":"MIT License","license_url":"https://opensource.org/license/mit","attribution":"Based on work by Seth Hobson (wshobson/agents, python-testing-patterns) (Copyright (c) 2024 Seth Hobson, MIT License), https://github.com/wshobson/agents/tree/7e2fb559cf4b824b27f1fec49fe88f7511066d26/plugins/python-development/skills/python-testing-patterns; adapted by TheSkillVault, https://theskillvault.ai","install":{"claude_code":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/raw' -o ~/'.claude/skills/write-python-tests-with-pytest/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/files/LICENSE.txt' -o ~/'.claude/skills/write-python-tests-with-pytest/LICENSE.txt'","cursor":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/raw' -o '.cursor/skills/write-python-tests-with-pytest/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/files/LICENSE.txt' -o '.cursor/skills/write-python-tests-with-pytest/LICENSE.txt'","agents":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/raw' -o '.agents/skills/write-python-tests-with-pytest/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/write-python-tests-with-pytest/files/LICENSE.txt' -o '.agents/skills/write-python-tests-with-pytest/LICENSE.txt'","mcp_url":"https://theskillvault.ai/mcp","cursor_mcp_deeplink":"cursor://anysphere.cursor-deeplink/mcp/install?name=theskillvault&config=eyJ1cmwiOiJodHRwczovL3RoZXNraWxsdmF1bHQuYWkvbWNwIn0%3D","mcp_config":{"mcpServers":{"theskillvault":{"url":"https://theskillvault.ai/mcp"}}}},"bundles":[],"tested_on":[{"family":"chatgpt","name":"ChatGPT","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"claude","name":"Claude","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"gemini","name":"Gemini","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"grok","name":"Grok","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"llama","name":"Llama","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"deepseek","name":"DeepSeek","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"mistral","name":"Mistral","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"qwen","name":"Qwen","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"kimi","name":"Kimi K","outcome":null,"date":null,"source":null,"counts":false,"stale":false}],"proven_rule":{"threshold":5,"window_days":365,"computed_at":"2026-11-02T03:20:33.817Z"}}