Playbooks · Coding agents
Add tests to an untested module with an agent
A solo builder adds the first tests to a module that has none, starting with the behaviour that already exists — not the behaviour they wish it had.
Audience: Solo builder · Stack: A Python module with no tests, in a project with a test runner already set up · Tool: GitHub Copilot Chat in VS Code, slash command /tests
Before you start
- A test runner already configured in the project, and one empty test file location you have chosen. If no runner exists, set one up first — generating tests into a project that cannot run them helps nobody.
- The module read once by you, end to end, before the agent sees it. You need to know what it does to judge whether a generated test describes real behaviour or invented behaviour.
- Copilot Chat available in your editor. The author cheat sheet lists
/testsas generating unit tests for the selected code, and notes that available slash commands vary by environment — check your own chat box if it is absent. - A rule for the session, stated up front: tests describe current behaviour first. New behaviour is a separate change, made after the tests exist.
Steps
- Pick one module, and within it one function that matters most — the one whose breakage would hurt first. Do not ask for tests for the whole module at once.
- Select that function in the editor and run
/testsin Copilot Chat. The author docs describe this command as creating a unit test for the current code selection. If your project uses a particular test framework, say so in the same prompt, using the framework's name as your project already uses it. - Read every generated test before running it. For each test, ask: does this assert something the code actually does, or something that sounds plausible? Delete or correct any test you cannot trace to the code.
- Run the new tests. Every test should pass on the unchanged module. A test that fails on unchanged code is either wrong or has found a real bug — find out which before continuing, and do not quietly edit the module to make a wrong test pass.
- Add one edge case yourself, by hand: an empty input, a zero, a missing value — whichever edge the module actually faces. Generated tests tend to cover the middle of the road; edges are where untested modules break.
- Repeat for the next function, one at a time, running the growing suite after each addition. Commit after each function, so a bad batch of tests is one commit to revert, not a pile to untangle.
- When the module has a suite that passes, change one line of the module deliberately, run the suite, and confirm a test fails. Then revert. This is the check that the suite actually guards anything.
Worked example
A solo builder has a Python module that formats invoice totals, with no tests. They select the function that computes a line total, run /tests, and get five tests. Reading them, they find one test asserting that a negative quantity raises an error — but the code happily multiplies it. That test is deleted, not “fixed” by changing the module, because the session's rule is current behaviour first. They add one hand-written edge case for quantity zero, run the suite, commit, and then deliberately change the rounding line to confirm a test fails before reverting. The suite now guards the module, and the negative-quantity question is recorded as a separate decision, not smuggled in as a test.
What can go wrong
- A generated test fails on unchanged code and you are tempted to fix the module to match. Fix: stop. Either the test is wrong, or you have found a bug. Decide which in the open, and record it — do not let a generated test silently redefine behaviour.
- The suite passes but a deliberate one-line break does not fail any test. Fix: the suite is decoration. Add tests for the broken line's behaviour before claiming coverage.
- Tests are generated for the whole module at once and half are wrong. Fix: delete the batch, pick one function, and redo it. Small batches are the method, not a fallback.
- The agent writes tests that depend on internal details that change often. Fix: prefer tests that call the function's public behaviour with real inputs and check real outputs.
Limits
- Generated tests can only describe what the agent understood from the code. If the code is wrong, a faithful test will faithfully lock in the wrong behaviour — which is why the deliberate-break check exists.
- A passing suite is not coverage. This page makes no coverage claim, because no coverage tool was run for it.
- Slash commands vary by environment, per the author docs. If
/testsis not offered in your editor, this playbook's central step does not apply as written.
Time and cost: NOT_MEASURED. This page gives no time or cost figure because the tool docs fetched for it state none that applies to this task.
Verification
Tier: AUTHOR_DOCS_VERIFIED · verified 2026-10-23. The workflow on this page was not run end to end in a sandbox for this page; every command, flag, and capability claim below was checked against an author doc or author repo fetched on 2026-10-23.
- https://docs.github.com/en/copilot/reference/chat-cheat-sheet
- https://docs.github.com/copilot/github-copilot-chat/using-github-copilot-chat-in-your-ide
Cut from this page, with reason:
- No test framework named: the reader's own framework is the input, so the page does not invent one.
- No coverage percentage: none was measured, so none is claimed.
- No time or cost figure: NOT_MEASURED.
If a step here does not match what your installed tool shows, trust the tool's own docs for your version and stop before approving a change you cannot read.
Back to: Coding playbooks hub (../../guides/coding/) · Skills index (../../skills/)