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=IntegrationThe 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