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.