Testing in C# (.NET): Frameworks and Tools for Developers

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Testing in C# (.NET): Overview of Frameworks and Tools



High-quality testing is the foundation of reliable software on the .NET platform. The C# ecosystem has several mature frameworks for unit, integration, and acceptance testing. In this article, we will review the main tools, their features, and provide practical code examples.



Main Frameworks for Unit Testing



In .NET Core and .NET 5+, built-in testing support is implemented through three main frameworks:



  • MSTest — the classic framework from Microsoft, simple for beginners.
  • NUnit — a popular open-source framework with a rich set of attributes.
  • xUnit.net — a modern, lightweight, and flexible tool created by the author of NUnit.


All three are supported in Visual Studio, Rider, and via the dotnet CLI. The choice depends on team preferences, but xUnit and NUnit are considered more flexible for complex scenarios.



Example Test with xUnit

Let's look at testing a simple calculator using xUnit:



using Xunit;

public class Calculator{ public int Add(int a, int b) => a + b; public int Divide(int a, int b) => b == 0 ? throw new DivideByZeroException() : a / b;}

public class CalculatorTests{ [Fact] public void Add_ShouldReturnSum_WhenTwoNumbers() { // Arrange var calc = new Calculator();

// Act var result = calc.Add(3, 5);

// Assert Assert.Equal(8, result); }

[Theory] [InlineData(10, 2, 5)] [InlineData(9, 3, 3)] [InlineData(7, 1, 7)] public void Divide_ShouldReturnQuotient(int a, int b, int expected) { var calc = new Calculator(); var result = calc.Divide(a, b); Assert.Equal(expected, result); }

[Fact] public void Divide_ShouldThrow_WhenDivideByZero() { var calc = new Calculator(); Assert.Throws<DivideByZeroException>(() => calc.Divide(5, 0)); }}


The [Fact] attribute denotes a regular test, while [Theory] with [InlineData] allows running one test with different input data.



Tools for Mock Objects



In unit testing, it is often necessary to isolate the class under test from external dependencies (databases, APIs, file system). Mock frameworks are used for this purpose:



  • Moq — the most popular, simple syntax, good documentation.
  • NSubstitute — more concise, with a fluent interface.
  • FakeItEasy — a friendly API for quickly creating stubs.


Example Using Moq

Suppose we have a service that sends emails. We want to test the logic without actual sending:



using Moq;using Xunit;

public interface IEmailSender{ void Send(string to, string subject, string body);}

public class NotificationService{ private readonly IEmailSender _sender; public NotificationService(IEmailSender sender) => _sender = sender;

public void NotifyUser(string email, string message) { if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Email is required"); _sender.Send(email, "Notification", message); }}

public class NotificationServiceTests{ [Fact] public void NotifyUser_ShouldCallSend_WhenValidEmail() { // Arrange var mockSender = new Mock<IEmailSender>(); var service = new NotificationService(mockSender.Object);

// Act service.NotifyUser("test@example.com", "Hello!");

// Assert mockSender.Verify(s => s.Send("test@example.com", "Notification", "Hello!"), Times.Once); } [

Recommendations