Unit Testing Mastery (xUnit, NUnit, MSTest)

    Write clean, maintainable tests that catch bugs before they reach production. Master the Arrange-Act-Assert pattern and advanced xUnit features.

    What You'll Learn

    • • Write tests with [Fact] and parameterized [Theory]
    • • Master assertion methods for strings, collections, types, and exceptions
    • • Use fixtures for shared setup with IClassFixture and ICollectionFixture
    • • Follow the Arrange-Act-Assert pattern consistently

    🧪 Real-World Analogy

    Unit tests are like a pilot's pre-flight checklist. Before every flight, pilots verify each system individually — engines, instruments, hydraulics. They don't wait until they're airborne to discover problems. [Fact] tests check one specific thing. [Theory] tests run the same check with different conditions — like testing instruments at different altitudes.

    xUnit Basics: Fact & Theory

    xUnit is the most popular .NET test framework. [Fact] marks a single test case. [Theory] with [InlineData] runs the same test with different inputs. Always follow the Arrange-Act-Assert pattern.

    xUnit Basics — Fact & Theory

    Write your first unit tests with parameterized data and exception assertions.

    Try it Yourself »
    C#
    using Xunit;
    
    // Calculator.cs — the class we're testing
    public class Calculator
    {
        public int Add(int a, int b) => a + b;
        public int Divide(int a, int b)
        {
            if (b == 0) throw new DivideByZeroException("Cannot divide by zero");
            return a / b;
        }
        public bool IsEven(int number) => number % 2 == 0;
    }
    
    // CalculatorTests.cs — xUnit test class
    public class CalculatorTests
    {
        private readonly Calculator _calc = new();
    
        // [Fact] — a single test case
        [Fact]
      
    ...

    Assertion Methods Deep Dive

    xUnit provides rich assertions for every data type — strings, collections, types, nullability, and async operations. Use the most specific assertion available for clearer failure messages.

    Assertion Methods Showcase

    Explore string, collection, type, async, and custom message assertions.

    Try it Yourself »
    C#
    using Xunit;
    using System.Collections.Generic;
    
    public class AssertionShowcase
    {
        // String assertions
        [Fact]
        public void StringAssertions_DemonstrateOptions()
        {
            string greeting = "Hello, World!";
    
            Assert.Equal("Hello, World!", greeting);
            Assert.StartsWith("Hello", greeting);
            Assert.EndsWith("World!", greeting);
            Assert.Contains("World", greeting);
            Assert.DoesNotContain("Goodbye", greeting);
            Assert.Matches("[A-Z][a-z]+, [A-Z][
    ...

    Test Fixtures & Shared Setup

    Use constructor/Dispose for per-test setup. For expensive resources (database, HTTP client), use IClassFixture (shared per class) or ICollectionFixture (shared across classes).

    Fixtures — Constructor, Class & Collection

    Share expensive setup across tests with IClassFixture and ICollectionFixture.

    Try it Yourself »
    C#
    using Xunit;
    using System;
    
    // Constructor/Dispose pattern — fresh setup for each test
    public class DatabaseTests : IDisposable
    {
        private readonly TestDatabase _db;
    
        // Runs BEFORE each test
        public DatabaseTests()
        {
            _db = new TestDatabase();
            _db.Seed();  // Insert test data
        }
    
        [Fact]
        public void GetUser_ExistingId_ReturnsUser()
        {
            var user = _db.GetUser(1);
            Assert.NotNull(user);
            Assert.Equal("TestUser", user.Name);
        }
    
       
    ...

    Pro Tip

    Name your tests with the pattern MethodName_Scenario_ExpectedResult (e.g., Add_TwoNegatives_ReturnsNegativeSum). This makes test failure reports self-documenting — you know exactly what broke without reading the test code.

    Common Mistakes

    • • Testing implementation instead of behavior — tests break on every refactor
    • • Sharing mutable state between tests — causes flaky, order-dependent failures
    • • Using Assert.True(x == y) instead of Assert.Equal(y, x) — worse error messages

    Lesson Complete!

    You've mastered unit testing fundamentals. Next, learn mocking frameworks to isolate dependencies in your tests.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service