█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/C# and .NET/Testing in C#
50 minIntermediate

Testing in C#

After this lesson, you will be able to: Write unit tests in C# with xUnit, mock dependencies with Moq, and assert fluently with FluentAssertions.

Testing in C# is mature: xUnit is the modern default, Moq + NSubstitute handle mocking, FluentAssertions reads like English. Real projects always have these.

Prerequisites:Unity intro

xUnit basics

Most popular .NET test framework. Run with `dotnet test`.

tsx
// Create test project: dotnet new xunit -o myapp.Tests
// Add reference: dotnet add reference ../myapp/myapp.csproj
using Xunit;
public class CalculatorTests {
[Fact]
public void Add_TwoPositives_ReturnsSum() {
var calc = new Calculator();
var result = calc.Add(2, 3);
Assert.Equal(5, result);
}
[Theory]
[InlineData(2, 3, 5)]
[InlineData(0, 0, 0)]
[InlineData(-1, 1, 0)]
public void Add_VariousInputs_ReturnsExpected(int a, int b, int expected) {
var calc = new Calculator();
Assert.Equal(expected, calc.Add(a, b));
}
[Fact]
public void Divide_ByZero_Throws() {
var calc = new Calculator();
Assert.Throws<DivideByZeroException>(() => calc.Divide(1, 0));
}
}

Mocking with Moq

Isolate the unit under test by faking its dependencies.

tsx
using Moq;
using Xunit;
public interface IEmailService {
Task SendAsync(string to, string subject);
}
public class UserService {
private readonly IEmailService _email;
public UserService(IEmailService email) { _email = email; }
public async Task RegisterAsync(string email) {
// ... save user
await _email.SendAsync(email, "Welcome!");
}
}
public class UserServiceTests {
[Fact]
public async Task RegisterAsync_SendsWelcomeEmail() {
var mockEmail = new Mock<IEmailService>();
var service = new UserService(mockEmail.Object);
await service.RegisterAsync("[email protected]");
mockEmail.Verify(e =>
e.SendAsync("[email protected]", "Welcome!"),
Times.Once);
}
}

FluentAssertions

Reads like English; better error messages.

html
using FluentAssertions;
// Plain Assert
Assert.Equal(5, result);
// FluentAssertions
result.Should().Be(5);
result.Should().BeGreaterThan(0).And.BeLessThan(10);
var users = new[] { "Alex", "Sam" };
users.Should().HaveCount(2);
users.Should().Contain("Alex");
users.Should().BeInAscendingOrder();
Action act = () => calc.Divide(1, 0);
act.Should().Throw<DivideByZeroException>();
// On error:
// Plain: Assert.Equal() Failure
// Fluent: Expected result to be 5, but found 4.

💡 Test what behavior, not implementation

Bad test: 'Verify that internal method X was called 3 times.' Breaks when refactoring. Good test: 'When I register, the user gets a welcome email.' Survives refactoring. Mock only at the boundary of your system (DB, email, external API). Don't mock your own internal classes.

Common mistakes

Mocking everything → tests pass but don't actually test the system. Asserting on private fields via reflection (extremely brittle). Single-test files with 50 tests (split by behavior). Naming tests `Test1`, `Test2` (use `Method_Scenario_ExpectedResult`).

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←C# for Game Dev: Unity Intro
Back to C# and .NET
Passion Project: ASP.NET Core REST API→