Unit Testing with xUnit

Intermediate 25 min read Lesson 2 of 6

Unit tests verify small pieces of your code behave correctly, and catch regressions automatically when you change something later.

Setting up a test project

dotnet new xunit -n MyProject.Tests
cd MyProject.Tests
dotnet add reference ../MyProject/MyProject.csproj

The code under test

public class DiscountCalculator
{
    public decimal ApplyDiscount(decimal price, decimal percent)
    {
        if (percent < 0 || percent > 100)
            throw new ArgumentOutOfRangeException(nameof(percent));

        return price - (price * percent / 100);
    }
}

Writing tests

using Xunit;

public class DiscountCalculatorTests
{
    [Fact]
    public void ApplyDiscount_TenPercentOff_ReturnsReducedPrice()
    {
        var calculator = new DiscountCalculator();

        decimal result = calculator.ApplyDiscount(100m, 10m);

        Assert.Equal(90m, result);
    }

    [Theory]
    [InlineData(100, 0, 100)]
    [InlineData(100, 50, 50)]
    [InlineData(200, 25, 150)]
    public void ApplyDiscount_VariousInputs_ReturnsExpected(
        decimal price, decimal percent, decimal expected)
    {
        var calculator = new DiscountCalculator();
        Assert.Equal(expected, calculator.ApplyDiscount(price, percent));
    }

    [Fact]
    public void ApplyDiscount_PercentOver100_ThrowsException()
    {
        var calculator = new DiscountCalculator();

        Assert.Throws<ArgumentOutOfRangeException>(() =>
            calculator.ApplyDiscount(100m, 150m));
    }
}

The AAA pattern

Every good test follows Arrange, Act, Assert:

  • Arrange — set up the object and inputs.
  • Act — call the method being tested.
  • Assert — check the result is what you expected.

Running tests

dotnet test

Or in Visual Studio: Test → Run All Tests, or open Test Explorer.

Key Takeaway

Unit testing catches bugs early and gives you confidence when making changes to your code.

Test Your Knowledge - Take Quiz