NUnit
01 / 02

Fixtures, Assertions & Parametrization

Fixtures, Assertions & Parametrization

Test Structure

using NUnit.Framework;

[TestFixture]
public class CalculatorTests
{
    private Calculator _calculator;

    [OneTimeSetUp]  // runs once for the whole fixture
    public void FixtureSetUp() => Console.WriteLine("Starting CalculatorTests");

    [SetUp]  // runs before every [Test]
    public void SetUp() => _calculator = new Calculator();

    [TearDown]  // runs after every test, pass or fail
    public void TearDown() => _calculator = null;

    [Test]
    public void Add_TwoPositiveNumbers_ReturnsSum()
    {
        var result = _calculator.Add(2, 3);
        Assert.That(result, Is.EqualTo(5));
    }

    [Test]
    public void Divide_ByZero_ThrowsException()
    {
        var ex = Assert.Throws<DivideByZeroException>(() => _calculator.Divide(10, 0));
        Assert.That(ex.Message, Does.Contain("zero"));
    }
}

// dotnet test                       — run everything
// dotnet test --filter Name~Add     — filter by name
// dotnet test --filter TestCategory=Integration

The Constraint Model

// Is.* — value comparisons
Assert.That(actual, Is.EqualTo(expected));
Assert.That(value, Is.Null);
Assert.That(price, Is.EqualTo(3.14).Within(0.01));       // float tolerance
Assert.That(count, Is.GreaterThan(0).And.LessThan(100)); // combinators

// Does.* — strings & collections
Assert.That(name, Does.StartWith("Al"));
Assert.That(text, Does.Match(@"^\d{3}-\d{4}$"));
Assert.That(numbers, Does.Contain(5));

// Has.* — object properties
Assert.That(user, Has.Property("Email").EqualTo("alice@example.com"));

// Collections
Assert.That(list, Is.Ordered);
Assert.That(list, Is.Ordered.By("Age").Descending);
Assert.That(resultSet, Is.EquivalentTo(new[] { 1, 2, 3 }));  // order-agnostic

// Multiple assertions reported together, not just the first failure
Assert.Multiple(() =>
{
    Assert.That(user.Name, Is.EqualTo("Alice"));
    Assert.That(user.Age, Is.EqualTo(30));
    Assert.That(user.IsActive, Is.True);
});

Parametrized Tests

[TestCase(2, 3, 5)]
[TestCase(-1, 1, 0)]
[TestCase(0, 0, 0)]
public void Add_VariousInputs_ReturnsExpectedSum(int a, int b, int expected)
{
    Assert.That(_calculator.Add(a, b), Is.EqualTo(expected));
}

// Complex data — pull from a static source instead of attribute literals
private static IEnumerable<TestCaseData> DivisionCases()
{
    yield return new TestCaseData(10, 2).Returns(5);
    yield return new TestCaseData(9, 3).Returns(3);
}

[TestCaseSource(nameof(DivisionCases))]
public int Divide_VariousInputs(int a, int b) => _calculator.Divide(a, b);

// Skip / expected-failure
[Ignore("Pending refactor — see JIRA-123")]
[Test]
public void OldBehavior_ToBeRemoved() { }

[Test]
[Category("Integration")]
public async Task FetchUser_ReturnsFromApi()
{
    var user = await _apiClient.GetUserAsync(1);
    Assert.That(user.Id, Is.EqualTo(1));
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free