Projects

VS2026 Unit Test Generator

A Visual Studio 2026 extension that analyzes service methods in an existing .NET project with Roslyn, extracts a complete test context including dependencies and data models, and hands it off to Copilot Chat to generate xUnit unit tests with a high coverage target.

C#RoslynxUnitGitHub CopilotVisual Studio SDKVSIX.NET 8

The Goal

Retrofitting unit tests onto an existing codebase is the job most teams keep putting off. The hard part isn't the test itself — it's gathering the context the test needs. If you're going to test a service method, reading that method isn't enough: you also need to know the private methods it calls, the injected dependencies, the DTOs that make up its return type and the entities behind them. Done by hand, that gathering takes minutes, and you repeat it for every method.

VS2026 Unit Test Generator takes over exactly that gathering work. Its goal is to generate xUnit unit tests for the services in an existing project, pushing code coverage as high as it can go.

💡

The extension doesn't rely on an additional mocking library; the generated tests are built entirely on xUnit.

How Does It Work?

The flow has four steps:

1. Multi-Select

In the extension window, you make a two-sided selection:

  • Which service methods to test (multi-select)
  • Which test service classes to write them to (multi-select)

That way, a single run can handle several methods and spread them across several test classes.

2. Context Extraction with Roslyn

Once the selection is made, the extension scans the codebase semantically through Roslyn and extracts everything the test needs:

CollectedWhy it's needed
Public method bodyThe actual behavior under test
Called private methodsYou can't target coverage without seeing the branches
Dependencies (interfaces)The exact signatures of the surface to satisfy in test setup
EntitiesThe real shape of the data model
DTOsInput/output contracts

This scan isn't a text search; it's compiler-level symbol resolution — in other words, a definitive answer to "which method actually calls what."

3. Pruning: 60% Context Savings

The collected context isn't sent to Copilot raw. A pruning step runs over the syntax tree that Roslyn provides: comment lines and code that contributes nothing to test generation are stripped out.

This step saves roughly 60% of the context. The gain is twofold: fewer tokens are spent, and the model's attention goes only to the code under test rather than to noise.

4. Clipboard → Copilot Chat

The pruned context package is copied to the Clipboard. All you have to do is paste it into the Copilot Chat window inside Visual Studio and hit Enter.

The package starts with the UnitTestWriter.agent.md prompt. This prompt is a contract of rules that keeps the model from improvising: the test framework to use, the naming convention, the Arrange/Act/Assert structure, how dependencies are satisfied and the number of test methods to generate are all enforced from here.

Clipboard contents
├── UnitTestWriter.agent.md      → framework rules and generation instructions
├── Target service method         → behavior under test
├── Called private methods        → branch map
├── Dependency interfaces         → signatures to satisfy
└── Entity + DTO definitions      → data contracts

The result: as many unit test methods as you chose, fully compliant with the framework rules and aiming for the highest possible coverage.

Why Does It Work Even with a Cheap Model?

This is the most striking part of the project. Even if you leave Copilot's model selection on Auto — that is, even if the tests are written the cheapest way possible — the output comes out highly accurate.

The reason is simple: the model is left nothing to guess.

Normally, when you ask a language model for a test, it has to guess what the dependencies return, which fields the DTO has and under which condition the private method takes which branch. Everything it guesses is a margin of error, and the usual way to close that margin is to switch to a more capable (and more expensive) model.

Here, all of that information is already present in the context, deterministically. The symbol information Roslyn extracts is exact and not open to interpretation. What's left for the model is to turn clear-cut data into a rule-abiding test method — a task small models handle with ease.

💡

The lesson: what determines the quality of generated code is less the model's intelligence and more the completeness and determinism of the context you give it. Build the context right and you no longer need the expensive model.

Tech Stack

  • Roslyn (.NET Compiler Platform): Symbol resolution over the semantic model, call graph extraction and syntax tree pruning
  • Visual Studio 2026 Extensibility Model (VisX): Tool window, multi-select UI and command integrations
  • VSIX Package: Extension manifest and distribution package
  • .NET 8: Extension runtime
  • xUnit: Target framework for the generated tests
  • GitHub Copilot Chat: Generation layer (steered by the agent prompt)

Use Cases

ScenarioDescription
Brownfield projectsBringing coverage in bulk to a codebase that has gone untested for years
Coverage thresholdsQuickly pushing services that struggle to meet the CI/CD pipeline's minimum coverage requirement above the threshold
Enforcing standardsMaking sure everyone on the team follows the same test-writing conventions, thanks to UnitTestWriter.agent.md
Cost controlUsing the corporate AI quota efficiently by running on the cheap model setting

Conclusion

VS2026 Unit Test Generator is less an application of the idea "let AI write our tests for us" and more an application of "let's ask AI the right question with the right context." Combine Roslyn's precision with Copilot's productivity and you get a test generation pipeline that is both fast and repeatable.

My favorite part is the economic one: once you prune the context by 60% and structure it properly, you can reach serious coverage numbers even on the cheapest model setting.

0

Comments

Be the first to comment

Share Your Thoughts

No comments yet. Be the first using the form above!
ME

Muhammed Emin Özdemir

Senior full-stack developer at VakıfBank. Focused on enterprise systems, clean code and LLM-based tools.

More about me →