You have a service class with twelve public methods, a handful of edge cases in each, and zero tests. The team agreed months ago that coverage needed improving. Nobody volunteered. That class is still sitting there, untested, quietly accumulating risk.
Visual Studio 2026 v18.3 introduced a feature aimed squarely at this problem: GitHub Copilot Testing for .NET. Unlike the general-purpose "write me a test" prompt you might fire into Copilot Chat, this is a dedicated agent workflow. It analyses your code, creates a test project if one does not exist, generates tests, builds them, runs them, detects failures, attempts fixes, and reruns until it reaches a stable baseline. It is the difference between asking a colleague to sketch a test on a whiteboard and handing the task to someone who will actually wire it up, run it, and tell you the results.
The feature went generally available in February 2026 and received a significant update in the "Supercharge" release shortly after. It supports MSTest, xUnit, and NUnit, works at scopes ranging from a single method to an entire solution, and is grounded in Roslyn and MSBuild rather than raw text generation. Here is how it works in practice and where it falls short.
The @Test Agent Workflow
The agent is invoked through Copilot Chat using the @Test participant. You can use structured syntax like @Test #MyClass or free-form natural language like @Test generate tests for the order validation logic. Both routes feed into the same underlying workflow.
Once invoked, the agent runs through a repeating cycle:
- Analyse the target code, its dependencies, and the project structure.
- Create a test project if the solution does not already contain one for the target.
- Generate unit tests covering the public surface area, edge cases, and common failure modes.
- Build the test project using Visual Studio's MSBuild integration (not the CLI).
- Run the generated tests via the Test Explorer APIs.
- Recover from failures by diagnosing the issue, adjusting the test code, and repeating from step 4.
This loop continues until the tests compile and pass, or the agent exhausts its retry budget. The result is not a text block you paste into a file — it is a set of test files already added to your solution, already passing, already visible in Test Explorer.
public class OrderValidator(IClock clock, IInventoryService inventory)
{
public async Task<ValidationResult> ValidateAsync(Order order)
{
if (order.Items.Count == 0)
return ValidationResult.Fail("Order must contain at least one item.");
if (order.RequestedDelivery < clock.UtcNow.AddDays(1))
return ValidationResult.Fail("Delivery must be at least 24 hours from now.");
foreach (var item in order.Items)
{
var available = await inventory.CheckStockAsync(item.Sku);
if (available < item.Quantity)
return ValidationResult.Fail($"Insufficient stock for {item.Sku}.");
}
return ValidationResult.Success();
}
}
Point the agent at this class — @Test #OrderValidator — and it will generate tests for the empty-items case, the delivery-date boundary, and the stock-check failure path. It will also set up mocks for IClock and IInventoryService, create the test project with the correct framework references, and run everything before handing control back to you.
Scoping: From a Single Method to an Entire Solution
One of the most practical aspects of the agent is its scoping model. You choose how much code to target:
- Single member:
@Test #ValidateAsyncgenerates tests for one method. - Class:
@Test #OrderValidatorcovers the full public API of a class. - File:
@Test #OrderValidator.cspicks up everything in the file. - Project:
@Test #MyApp.Coregenerates tests across an entire project. - Solution:
@Test #solutiontargets the whole solution. This is the "go make coffee" option. - Git diff:
@Test #git_changesgenerates tests only for code you have changed since the last commit.
The git diff scope is particularly useful during code review. Before pushing a PR, run @Test #git_changes to generate tests covering your modifications. It will not touch the rest of the codebase.
// TIP
Start with class-level scope. Solution-wide generation works but produces a large volume of tests that take time to review. Class-level scope gives you enough coverage to validate the workflow without drowning in output.
Free-Form Prompting
The structured @Test #target syntax is convenient, but the agent also accepts natural language. This is where it gets interesting for more targeted scenarios:
@Test generate unit tests for the retry logic in HttpClientWrapper
@Test class PaymentProcessor, targeting 80% code coverage
@Test write edge case tests for the date parsing in CsvImporter
The agent interprets your intent and maps it to the appropriate scope and generation strategy. You are not constrained to a rigid command format. The free-form syntax is especially useful when you want to emphasise a particular aspect — edge cases, error paths, or a specific coverage target.
What Happens Under the Hood
The agent is not just prompting a language model and pasting the output. It is built on three pillars that distinguish it from generic Copilot Chat:
Roslyn integration. The agent understands your type system, project references, and C# semantics. It knows which types are disposable, which methods are async, and which parameters are nullable. This means generated tests are type-safe and structurally correct far more often than freehand LLM output.
MSBuild and project system awareness. When the agent creates a test project, it adds the correct framework references, respects your existing NuGet package versions, and configures InternalsVisibleTo if needed. It uses Visual Studio's project system APIs rather than shelling out to dotnet commands.
Test Explorer integration. Tests are run through the same Test Explorer infrastructure you use for your own tests. Results appear inline. Coverage deltas are computed automatically, and the post-generation summary shows before-and-after coverage numbers.
The agent also installs NuGet packages as needed — test framework packages, mocking libraries, and coverage extensions for Microsoft Test Platform. It uses a scoped file system that prevents writes outside the repository root.
Entry Points Beyond Chat
While @Test in Copilot Chat is the primary interface, the agent is accessible from several places:
Right-click context menu. Right-click on a class, method, or file in the editor and select Copilot Actions > Generate Tests. The scope is inferred from your cursor position. This is the fastest route when you are already reading the code you want to test.
Icebreaker prompts. When you open Copilot Chat with a C# file focused, pre-populated prompts appear that launch the testing agent scoped to your current document.
Test Explorer. For projects that already have partial coverage, the agent can identify untested areas and generate tests to fill the gaps.
Where It Works Well
The agent excels in specific scenarios:
Greenfield test coverage. When a project has zero tests, the agent can bootstrap a meaningful test suite in minutes. It handles the boilerplate — project creation, framework setup, mock scaffolding — that makes starting from scratch so tedious.
Deterministic logic. Pure functions, validators, parsers, and calculation engines produce the best results. The agent can reason about inputs, outputs, and edge cases without needing external context.
Refactoring confidence. Before a large refactor, run the agent against the classes you plan to change. The generated tests serve as a regression safety net, even if they are not the tests you would write by hand.
PR coverage gates. The #git_changes scope fits naturally into a workflow where coverage gates block merges. Generate tests for your diff, review them, and push.
Where It Struggles
No tool is honest about its limitations in its own marketing material, so here is the practical reality:
Complex integration scenarios. The agent generates unit tests, not integration tests. If your class depends heavily on database state, external APIs, or message queues, the generated mocks will be syntactically correct but semantically shallow. A mock that returns Task.CompletedTask tells you nothing about whether the real dependency behaves the way you expect.
Stateful workflows. Multi-step processes where test setup requires building complex object graphs or executing a sequence of operations in a specific order tend to produce brittle, hard-to-follow tests. The agent does not understand your domain invariants — it understands your type signatures.
Test quality versus test existence. The agent optimises for tests that compile and pass. That is not the same as tests that catch real bugs. A test that asserts result != null when the method never returns null is technically passing but practically useless. You still need to review generated tests with the same critical eye you would apply to a colleague's PR.
Large scope generation. Solution-wide generation works but produces an overwhelming number of tests. Reviewing hundreds of generated test files is its own time sink. The team at Microsoft has acknowledged this and is actively exploring a planning phase for larger requests, where you would review a proposed test plan before generation begins.
Common Pitfalls
Treating generated tests as done. The biggest mistake is merging generated tests without review. The agent produces a starting point, not a finished product. Rename test methods to describe the scenario, not the implementation. Remove redundant assertions. Add the edge cases the agent missed.
Running against code that does not build. The agent requires a clean build to start. If your project has compilation errors, the agent will fail immediately. Fix your build first.
Ignoring the coverage summary. The post-generation summary includes before-and-after coverage numbers, pass/fail counts, and testability gap insights. Read them. The testability gaps often highlight design issues — static method dependencies, hidden side effects, or tight coupling — that are worth fixing regardless of test coverage.
Expecting it to replace test-driven development. The agent works backwards from existing code. It cannot drive your design. If you practise TDD, the agent is useful for backfilling coverage on legacy code, not for guiding new development.
// WARNING
The security consent dialog is not a formality. When you grant the agent permission to execute LLM-generated code, you are allowing it to install NuGet packages and run arbitrary test code in your Visual Studio session. Microsoft recommends running this in a sandboxed environment, particularly if your GitHub account has write access to production repositories.
Configuration and Requirements
The feature requires Visual Studio 2026 v18.3 or later, a C# project, and a paid GitHub Copilot subscription (Individual, Business, or Enterprise). The free Copilot tier is not supported.
Configuration lives under Tools > Options > GitHub > Copilot > Testing. The most important setting is the consent toggle for executing LLM-generated code. Beyond that, the agent respects your existing test framework conventions — if your solution already uses xUnit, new tests will use xUnit. If no tests exist, it defaults to MSTest.
The agent supports any model available in your Copilot Chat model selector. Model choice affects generation quality: larger models produce more nuanced edge-case coverage, while faster models trade depth for speed.
Summary
- GitHub Copilot Testing for .NET is a purpose-built agent workflow in Visual Studio 2026, not a generic chat prompt.
- It generates, builds, runs, and self-heals C# unit tests using Roslyn, MSBuild, and Test Explorer integration.
- Scope from a single method to an entire solution, or target only your git diff.
- Best suited for bootstrapping coverage on untested code, deterministic logic, and pre-refactor safety nets.
- Generated tests are a starting point that requires review — they optimise for compilation and passing, not for catching real bugs.
- Requires a paid Copilot subscription and Visual Studio 2026 v18.3 or later.