Unit Testing with xUnit 3 and Copilot
In this lesson, you will learn how to write better unit tests with xUnit 3, generate test ideas with Copilot, use mocks to isolate dependencies, and measure how much of your code is covered by tests.
← Back to Visual Studio 2026 Tutorial HomeWhat you will learn
- What unit testing is and why it matters
- How xUnit 3 structures test methods and test data
- How Copilot can help generate and improve tests
- How mocking frameworks isolate dependencies
- How code coverage helps reveal untested logic
Part 1: Understanding xUnit 3
xUnit is a popular testing framework for .NET. It lets you write automated tests that verify whether your code behaves as expected. xUnit 3 continues the same clean style while improving the testing experience for modern .NET development.
A unit test usually focuses on one small piece of behavior, such as a calculation, validation rule, or service method.
[Theory]
[ClassData(typeof(OrderTestData))]
public async Task ProcessOrder_ValidatesTotal(Order order, decimal expected)
{
var result = await _service.ProcessAsync(order);
Assert.Equal(expected, result.Total);
}
In this example, the same test logic runs with different data inputs. That is useful when you want to verify the same rule under multiple conditions.
Part 2: Writing effective unit tests
A good unit test should be easy to read, easy to maintain, and focused on one behavior. A common pattern is:
- Arrange — prepare the inputs and dependencies
- Act — call the method being tested
- Assert — verify the result
CalculateTotal_ReturnsZero_WhenCartIsEmpty.
Part 3: AI-assisted test generation with Copilot
Visual Studio 2026 can use Copilot to help generate test ideas and boilerplate. This can save time, especially when writing repetitive test setups or identifying edge cases you may have missed.
For example, Copilot may suggest tests for:
- Normal successful input
- Null or empty values
- Boundary values
- Thrown exceptions
- Async and cancellation behavior
Part 4: Mocking dependencies with NSubstitute
Many methods depend on repositories, APIs, loggers, or other services. In unit tests, you usually do not want to call the real dependency. Instead, you replace it with a mock or substitute.
repo.GetByIdAsync(Arg.Any<int>())
.Returns(Task.FromResult(new Order { Id = 1, Total = 99.99m }));
// Verify it was called
await repo.Received(1).GetByIdAsync(1);
This lets you isolate the method under test and verify how it interacts with other components.
Part 5: Code coverage and Hot Coverage
Code coverage shows which parts of your code were executed by your tests. It does not guarantee correctness, but it helps reveal areas that have not been tested at all.
Visual Studio 2026 includes Hot Coverage, which can show live coverage information while you work.
- Green gutter indicates covered code
- Red gutter indicates uncovered code
- Coverage reports help you focus on missing test areas
When to use each testing tool
| Tool or concept | Best used for |
|---|---|
| xUnit | Writing and organizing automated unit tests |
| Theory and data-driven tests | Testing the same logic with multiple input values |
| Copilot test generation | Getting test suggestions and saving setup time |
| NSubstitute | Replacing dependencies with test doubles |
| Coverage tools | Finding code paths that are not exercised by tests |
A practical unit testing workflow
Best practices
- Write small, focused tests
- Prefer readable test names
- Test behavior, not internal implementation details
- Use mocking only when needed
- Review AI-generated tests before trusting them
- Keep your tests fast so they run often
Summary
In this lesson, you learned how xUnit 3 supports unit testing in modern .NET projects, how Copilot can help generate tests, how mocking frameworks isolate dependencies, and how coverage tools reveal untested areas.
In the next lesson, you will explore performance profiling and diagnostics in Visual Studio 2026.