Unit Testing with xUnit in .NET: Complete Beginner's Guide

Writing code is only part of software development. Ensuring that code works correctly and continues to work after future changes is equally important.

Unit testing helps developers verify that individual components behave as expected. In the .NET ecosystem, xUnit is one of the most popular testing frameworks and is widely used in professional applications.

In this guide, you'll learn how to create unit tests with xUnit, write assertions, test business logic, mock dependencies, and follow testing best practices.


Topics Covered
  • What Is Unit Testing?
  • Why Unit Tests Matter
  • Installing xUnit
  • Creating Test Projects
  • Writing Test Methods
  • Using Assertions
  • Testing Services
  • Mocking Dependencies
  • Common Mistakes
  • Best Practices

What Is Unit Testing?

Unit testing is the process of testing small pieces of code, usually individual methods or classes, in isolation.

The goal is to verify that each unit behaves correctly under different conditions.

Benefits of Unit Testing

  • Detect bugs early.
  • Improve code quality.
  • Increase confidence when refactoring.
  • Reduce manual testing effort.
  • Improve maintainability.

Create a Test Project

Create a new xUnit project using the .NET CLI.


        dotnet new xunit -n MyApp.Tests
    

Add the test project to your solution.


        dotnet sln add MyApp.Tests
    

Project Structure


        MyApp
        │
        ├── Services
        │   └── CalculatorService.cs
        │
        MyApp.Tests
        │
        └── CalculatorServiceTests.cs
    

Create a Service to Test


        public class CalculatorService
        {
        public int Add(int a, int b)
        {
        return a + b;
        }
        }
    

Write Your First xUnit Test


        using Xunit;

        public class CalculatorServiceTests
        {
        [Fact]
        public void Add_ReturnsCorrectResult()
        {
        var calculator =
        new CalculatorService();

        int result =
        calculator.Add(5, 3);

        Assert.Equal(8, result);
        }
        }
    

The Fact attribute identifies a test method.

Running Tests


        dotnet test
    

The test runner executes all test methods and reports successful and failed tests.

Understanding Assertions

Assertions verify expected outcomes.


        Assert.Equal(10, result);

        Assert.True(isValid);

        Assert.False(hasErrors);

        Assert.NotNull(user);

        Assert.Contains("Admin", roles);
    

Testing Multiple Inputs

Use Theory and InlineData to test several scenarios.


        [Theory]
        [InlineData(2, 3, 5)]
        [InlineData(10, 5, 15)]
        [InlineData(1, 1, 2)]
        public void Add_ReturnsExpectedResult(
        int a,
        int b,
        int expected)
        {
        var calculator =
        new CalculatorService();

        int result =
        calculator.Add(a, b);

        Assert.Equal(expected, result);
        }
    

Testing Exceptions


        [Fact]
        public void Divide_ByZero_ThrowsException()
        {
        Assert.Throws<DivideByZeroException>(
        () => 10 / int.Parse("0"));
        }
    

Testing Business Logic


        public class DiscountService
        {
        public decimal ApplyDiscount(
        decimal price)
        {
        return price * 0.9m;
        }
        }
    

        [Fact]
        public void ApplyDiscount_Returns10PercentOff()
        {
        var service =
        new DiscountService();

        decimal result =
        service.ApplyDiscount(100);

        Assert.Equal(90, result);
        }
    

Mocking Dependencies

Real applications often depend on databases, APIs, or external services.

Mocking allows tests to run without relying on external systems.

Install Moq


        dotnet add package Moq
    

Example Interface


        public interface IEmailService
        {
        void Send(string message);
        }
    

Mock the Dependency


        using Moq;

        var emailMock =
        new Mock<IEmailService>();

        emailMock
        .Setup(e => e.Send(It.IsAny<string>()));
    

Mock objects simulate behavior without sending actual emails or connecting to databases.

Unit Testing in ASP.NET Core

Unit testing is commonly used for:

  • Services
  • Business Logic
  • Repositories
  • Validation Rules
  • Controllers

Common Beginner Mistakes

  • Testing multiple behaviors in one test.
  • Writing overly complex tests.
  • Testing database infrastructure directly.
  • Ignoring edge cases.
  • Using unclear test names.

Best Practices

  • Keep tests small and focused.
  • Test one behavior per test method.
  • Use descriptive test names.
  • Mock external dependencies.
  • Run tests automatically in CI/CD pipelines.
  • Maintain high test coverage for business logic.

Frequently Asked Questions

What is xUnit?

xUnit is a popular open-source testing framework for .NET applications.

Is xUnit better than MSTest?

Both are good frameworks. xUnit is widely adopted in modern .NET projects and has strong community support.

Should I test controllers?

Focus primarily on business logic and services. Controllers can be tested when they contain important logic.

What percentage of code should be tested?

There is no perfect number, but critical business logic should have strong test coverage.

Related Tutorials

Conclusion

Unit testing is an essential skill for every .NET developer. It helps prevent bugs, improve maintainability, and increase confidence when making changes to an application.

By learning xUnit, assertions, mocking, and testing best practices, you'll be able to create more reliable ASP.NET Core and .NET applications.