How to Write Tests with GitHub Copilot
Use GitHub Copilot to draft tests for existing code or test-first development. Learn how to prompt, review, run, and troubleshoot the results.
GitHub Copilot can draft unit tests for existing code and help you write tests before implementation. To get useful results, name the behavior, testing framework, relevant edge cases, and local project conventions. Then review the generated assertions and run the tests: Copilot can miss scenarios or encode assumptions that your requirements do not support.
1. Prepare the code and project context
Open the function, class, or file you want to test. Before prompting, identify:
- The behavior under test: what the code should do, including important business rules.
- The framework: for example, the test framework already used by the project.
- Project conventions: test file locations, naming, fixtures, setup, and assertion style.
- Scenarios: normal inputs, boundary values, invalid inputs, exceptions, and relevant side effects.
Existing test files are useful context. Open a nearby example or reference it in your prompt so Copilot can follow the project’s patterns. Do not rely on it to infer undocumented requirements.
2. Generate tests for existing code
In Copilot Chat, ask for tests for the active file or selected code. You can also use the /tests command to request tests for existing code. Be explicit about behavior and scenarios rather than asking only for a “comprehensive” suite.
Write tests for the validateEmail function using the project's existing test framework.
Follow the patterns in the nearby validation test file.
Cover valid addresses, empty input, malformed addresses, boundary-length input,
and any documented exceptions. Use descriptive test names and independent tests.
Do not assume business rules that are not stated. List unclear requirements before
encoding them as assertions.
Adapt the function, framework, and scenarios to your codebase. The prompt asks for behavior-focused tests without prescribing implementation details.
3. Ask for tests before implementation
For test-driven development, describe the desired behavior and ask Copilot to draft tests before the implementation exists. Use an ordinary prompt rather than /tests, which is intended to write tests for existing code.
I'm implementing a function that [describe the desired behavior].
Using [framework] and the conventions in [existing test file], draft tests first.
Cover [normal cases], [boundary cases], and [invalid or error cases].
Include relevant side effects or dependency interactions.
Do not invent requirements; list ambiguities before asserting behavior.
Review the proposed cases against the actual specification before writing code to satisfy them. A generated test is a draft of expected behavior, not proof that the requirement was understood correctly.
4. Review and run the generated suite
- Check that each test asserts an observable result or documented side effect.
- Compare the cases with the requirements. Add missing branches, boundaries, invalid inputs, and error paths.
- Remove assertions based on unstated assumptions or internal implementation details that may change without changing behavior.
- Check that tests are independent and use the project’s normal setup, fixtures, and cleanup.
- Run the tests with the project’s usual command and investigate failures. A passing generated suite does not prove complete coverage.
GitHub’s guidance also recommends reviewing generated tests because they may not cover every scenario. Treat coverage reports as clues to untested code, not as a substitute for deciding which behaviors matter.
5. Make prompts more precise
| Prompt detail | What to include |
|---|---|
| Target | The function, class, selected code, or behavior to test. |
| Framework | The project’s test framework and any relevant conventions. |
| Expected behavior | Inputs and outcomes required by the specification. |
| Edge cases | Boundaries, invalid values, empty values, and exceptional conditions that matter. |
| Interactions | Relevant calls to dependencies, emitted events, state changes, or other side effects. |
| Context | A nearby test file or pattern for setup, naming, and assertions. |
| Constraints | Ask Copilot to surface ambiguities rather than turn guesses into assertions. |
A reusable template is:
Write tests for [function or behavior] using [framework]. Follow the patterns in
[existing test file]. Cover [normal cases], [boundary cases], and [invalid or error
cases]. Include [relevant side effects or dependency interactions]. Do not assume
business rules that are not stated; list any unclear requirement before encoding it
in an assertion.
GitHub’s reusable unit-test prompt example also recommends descriptive test names, Arrange–Act–Assert structure, independent tests, and testing behavior rather than implementation details. Prompt-file availability and preview status can change; check GitHub’s current documentation if you plan to use prompt files.
6. Troubleshoot common problems
| Symptom | Likely cause | What to do |
|---|---|---|
| Tests use the wrong framework or file layout | The prompt did not specify the framework, or Copilot lacked examples. | Name the framework and open or reference a nearby test file with the project’s conventions. |
| Assertions encode unexpected business rules | The requirements were incomplete or Copilot inferred behavior. | Check every assertion against the specification; state the rule explicitly or ask Copilot to list ambiguities. |
| Important cases are missing | The scenario list was too broad or omitted boundaries and failure paths. | Prompt separately for representative inputs, boundary values, invalid inputs, exceptions, and relevant side effects; inspect untested branches. |
| Tests are brittle | Assertions depend on implementation details or shared mutable setup. | Assert documented behavior, make tests independent, and follow existing fixture and cleanup patterns. |
| Generated tests fail immediately | The draft may misunderstand the API, setup, fixtures, or intended behavior. | Read the failure and test code, correct unsupported assumptions, and rerun using the project’s normal test command. |
/tests is a poor fit for tests-first work |
The command targets existing code. | Describe the intended behavior in a normal chat prompt before implementation. |
7. Practical limits and workflow costs
Copilot-generated tests still need developer review and execution. The result depends on the context it can inspect and the clarity of the requirements. A large request can produce a long draft that is harder to validate; splitting work by function or behavior can make omissions and incorrect assumptions easier to spot. No coverage, time-saving, or productivity figure is implied here.
8. ScreenshotNeo alternative for screenshot-based tests
If your tests need website screenshots as visual artifacts, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It complements Copilot-generated tests by providing screenshots; it does not write or verify your test assertions.
Or skip the browser setup
Make one GET request to capture a page as an image. See the ScreenshotNeo API documentation for options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for AI agents. - 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
9. Frequently asked questions
Can Copilot guarantee complete test coverage?
No. Review the scenarios and branches against your requirements, then run the tests and add missing cases.
Should I use /tests for test-driven development?
For tests before implementation, use a regular prompt describing the desired behavior. The documented /tests workflow is for existing code.
What if the requirements are ambiguous?
Ask Copilot to list unclear points, then resolve them against the actual specification before making them assertions.


