NUnit Cheat Sheet for C# Developers: A Complete Guide to Unit Testing

If you're building anything in C#, and you're not writing tests - you're missing out on one of the most powerful tools in your developer toolbox. NUnit is a mature, flexible, and widely adopted unit testing framework for .NET. It’s been around for years, and it’s still one of the best ways to write clean, maintainable, and automated tests for your code.

This cheat sheet is your friendly guide to mastering NUnit - from writing your first test to advanced scenarios like parameterized tests, exception assertions, test fixtures, setup/teardown logic, and even custom test data sources. Whether you're just starting out or you're looking to level up your testing game, this article has you covered.

Installing NUnit

First things first - you’ll need to install NUnit and the NUnit3TestAdapter so Visual Studio (or your CI pipeline) can discover and run your tests.

// In Package Manager Console
Install-Package NUnit
Install-Package NUnit3TestAdapter

Once installed, create a new test project (usually a separate project in your solution), and start writing tests in classes decorated with [TestFixture].

Your First Test

Let’s start with a simple example. Suppose you have a method that adds two numbers. Here’s how you’d test it:

using NUnit.Framework;

[TestFixture]
public class CalculatorTests
{
    [Test]
    public void Add_TwoNumbers_ReturnsSum()
    {
        var result = 2 + 3;
        Assert.AreEqual(5, result);
    }
}

That’s it - your first test! The [Test] attribute marks the method as a test case, and Assert.AreEqual checks that the result is what you expect.

Understanding Assertions

NUnit provides a rich set of assertions to verify behavior. Here are some of the most commonly used:

  • Assert.AreEqual(expected, actual)
  • Assert.IsTrue(condition)
  • Assert.IsFalse(condition)
  • Assert.IsNull(object)
  • Assert.IsNotNull(object)
  • Assert.Throws<ExceptionType>(() => method())
// Example
Assert.AreEqual(42, myService.GetAnswer());
Assert.IsTrue(user.IsActive);
Assert.Throws(() => calculator.Divide(1, 0));
Always write assertions that clearly express intent. Avoid overly clever logic - tests should be easy to read and understand.

Setup and Teardown

Often, you’ll need to initialize some state before each test runs. NUnit provides [SetUp] and [TearDown] for this.

private Calculator _calculator;

[SetUp]
public void Init()
{
    _calculator = new Calculator();
}

[TearDown]
public void Cleanup()
{
    _calculator = null;
}

[SetUp] runs before each test, and [TearDown] runs after. There’s also [OneTimeSetUp] and [OneTimeTearDown] for class-level setup.

Parameterized Tests with [TestCase]

Want to test multiple inputs without duplicating code? Use [TestCase]:

[TestCase(2, 3, 5)]
[TestCase(0, 0, 0)]
[TestCase(-1, -1, -2)]
public void Add_ValidInputs_ReturnsExpected(int a, int b, int expected)
{
    var result = a + b;
    Assert.AreEqual(expected, result);
}

This is great for simple input/output scenarios. You can also use [TestCaseSource] for more complex data.

Advanced: TestCaseSource and Custom Data

Sometimes you need more flexibility than [TestCase] allows. Enter [TestCaseSource]:

static object[] AddCases =
{
    new object[] { 1, 2, 3 },
    new object[] { -1, -1, -2 }
};

[Test, TestCaseSource(nameof(AddCases))]
public void Add_FromSource(int a, int b, int expected)
{
    Assert.AreEqual(expected, a + b);
}

You can also use methods or external files as sources. This is especially useful for testing edge cases or large datasets.

Exception Testing

You’ll often want to verify that your code throws the right exceptions. NUnit makes this easy:

[Test]
public void Divide_ByZero_ThrowsException()
{
    Assert.Throws(() => calculator.Divide(10, 0));
}

You can also capture the exception and inspect it:

var ex = Assert.Throws(() => service.DoSomething(null));
Assert.That(ex.Message, Is.EqualTo("Input cannot be null"));

Using Categories

Want to group tests? Use [Category]:

[Test]
[Category("Math")]
public void Multiply_TwoNumbers()
{
    Assert.AreEqual(6, 2 * 3);
}

You can then run tests by category in your test runner or CI pipeline.

Asserting Collections

NUnit has built-in support for asserting collections:

var actual = new[] { 1, 2, 3 };
var expected = new[] { 1, 2, 3 };

Assert.That(actual, Is.EqualTo(expected));
Assert.That(actual, Has.Member(2));
Assert.That(actual, Is.All.GreaterThan(0));
Assert.That is more expressive and flexible than traditional assertions. It’s worth learning!

Combining Constraints

NUnit’s constraint model lets you write fluent assertions:

Assert.That(value, Is.Not.Null.And.GreaterThan(0));
Assert.That(name, Does.StartWith("Vaibhav").And.EndWith("Lawand"));

This makes your tests more readable and expressive.

Ignoring Tests

Sometimes you want to skip a test temporarily. Use [Ignore]:

[Test]
[Ignore("Waiting for bug fix")]
public void FeatureX_NotReadyYet()
{
    // test code
}

Running Tests

In Visual Studio, hit Ctrl + R, A to run all tests. You can also run tests via the command line:

dotnet test

You can filter by category, name, or even traits using command-line options.

Mocking and Isolation

NUnit works great with mocking frameworks like Moq. Here’s a quick example:

var mockRepo = new Mock();
mockRepo.Setup(r => r.GetUser("vaibhav")).Returns(new User { Name = "Vaibhav" });

var service = new UserService(mockRepo.Object);
var user = service.GetUser("vaibhav");

Assert.AreEqual("Vaibhav", user.Name);

This lets you isolate dependencies and test behavior without relying on real implementations.

Best Practices

  • Keep tests small and focused - one assertion per test is ideal.
  • Use descriptive names - Should_Throw_When_InputIsNull beats Test1.
  • Prefer pure functions - they’re easier to test and reason about.
  • Use setup methods to avoid duplication.
  • Group related tests into fixtures.
  • Run tests often - ideally on every commit via CI.

Common Mistakes

  • Testing too much in one method - split into smaller tests.
  • Not asserting anything - a test without assertions is just noise.
  • Relying on external state - tests should be isolated and repeatable.
  • Ignoring edge cases - test nulls, empty strings, and boundary values.
  • Skipping exception tests - always verify error handling.

Summary

NUnit is a powerful and flexible framework that makes testing in C# a joy. From basic assertions to advanced parameterized tests, it gives you everything you need to write clean, maintainable, and automated tests. The key is to write tests that are readable, focused, and expressive - and to run them often.