Unit test in C# using xUnit

Uğur Can Yıldırım
Deeper Deep Learning TR
6 min readDec 12, 2022

One of the key tools that can help you to develop and maintain high-quality C# code is unit testing. In this article, we will explore what C# unit testing is, why it is important, and how to get started with it.

What is C# unit testing?

C# unit testing is the practice of testing individual units of code in a C# application. A unit is the smallest testable part of an application, and typically corresponds to a single class or method. When you perform C# unit testing, you create special test methods that exercise the functionality of these individual units and verify that they are working correctly.

Why is unit testing important?

There are several reasons why unit testing is important:

1. Unit testing can help you to catch bugs early in the development process. By writing and running test methods for each unit of your code, you can quickly identify and fix any issues before they become more difficult and costly to fix later on.

2. Unit testing can help you to ensure that your code is correct and reliable. By verifying that each unit of your code is working correctly, you can build confidence in the overall quality and reliability of your application.

3. Unit testing can help you to make changes to your code with confidence. When you make changes to your code, you can re-run your unit tests to ensure that the changes did not introduce any new bugs or break existing functionality.

4. Unit testing can help you to improve the design of your code. By writing unit tests, you can gain a better understanding of the dependencies and interactions between different units of your code. This can help you to identify opportunities to refactor your code and make it more modular, flexible, and maintainable.

How to get started with Unit testing

To get started with C# unit testing, you will need to set up a testing framework and create some test methods for your code. Here are the steps to follow:

1. Choose a testing framework. There are several options available for C# unit testing, including NUnit, xUnit, and MSTest. Each of these frameworks has its own strengths and weaknesses, so you should choose the one that best meets your needs.

2. Install the testing framework. Most testing frameworks are available as NuGet packages, which makes it easy to install them in your C# project. Simply use the NuGet Package Manager to search for the framework you want to use and install it in your project.

3. Create a test class. In your C# project, create a new class to contain your unit tests. This class should be decorated with a special attribute that tells the testing framework that it contains test methods.

4. Write test methods. In your test class, write one or more methods that test the functionality of individual units of your code. Each test method should contain assertions that verify that the unit is working correctly.

5. Run your tests. Use the testing framework to run your test methods and verify that they are working correctly. Most testing frameworks provide tools for running and debugging tests, including the ability to run all tests or individual tests, and to see the results of the tests.

In the following example we will use xUnit and AAA pattern. Let’s learn about AAA pattern and then jump into examples.

AAA, or Arrange-Act-Assert, is a common pattern used in writing tests. The pattern consists of three steps:

  1. Arrange: In this step, you set up the objects and data that are needed for the test. This often involves creating instances of classes, initializing variables, and providing input data.
  2. Act: In this step, you perform the actual action that you want to test. This often involves calling a method or function and storing the result in a variable.
  3. Assert: In this step, you verify that the result of the action is what you expected. This often involves using an assertion library like Assert in xUnit, Expect in Jasmine, or assertThat in JUnit, to check if the result is equal to, greater than, or less than the expected value.

The AAA pattern is useful because it helps you organize your tests in a clear and consistent way, making it easier to read and understand what the test is doing. It also helps you isolate the code that you are testing, making it easier to identify and fix any errors or bugs.

Now let’s go through some examples

public class Calculator
{
public double Sum(double number1, double number2) => number1 + number2;
public double Average(List<double> numberList) => numberList.Average();
public double Divide(int numerator, int denominator) => numerator / denominator;
}

To test Calculator class with xUnit


public class CalculatorTests
{
[Theory]
[InlineData(2, 3, 5)]
[InlineData(4, 5, 9)]
public void Sum_ReturnsExpectedResult(double number1, double number2, double expectedResult)
{
//Arrange
var calculator = new Calculator();
//Act
var result = calculator.Sum(number1, number2);
//Assert
Assert.Equal(expectedResult, result);
}
[Theory]
[InlineData(10, 5, 2)]
[InlineData(20, 10, 2)]
[InlineData(15, 3, 5)]
public void Divide_ReturnsExpectedResult(int numerator, int denominator, int expectedResult)
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Divide(numerator, denominator);
// Assert
Assert.Equal(expectedResult, result);
}
[Fact]
public void Divide_ThrowsDivideByZeroException()
{
// Arrange
var calculator = new Calculator();
var numerator = 10;
var denominator = 0;
// Act and Assert
Assert.Throws<DivideByZeroException>(() => calculator.Divide(numerator, denominator));
}
[Theory]
[MemberData(nameof(DataForAverageTests))]
public void Average_ReturnsExpectedResult(List<double> numberList, double expectedResult)
{
//Arrange
var calculator = new Calculator();
//Act
var result = calculator.Average(numberList);
//Assert
Assert.Equal(expectedResult, result);
}
public static IEnumerable<object[]> DataForAverageTests()
{
yield return new object[] { new List<double> { 1, 2, 3, 4, 5 }, 3 };
yield return new object[] { new List<double> { 10, 15, 20 }, 15 };
yield return new object[] { new List<double> { -5, -10, -15 }, -10 };
}
}

In this example, we are testing the Sum , Divideand Average methods of the Calculator class. The [Fact] and [Theory] attributes indicates that the following method is a test. The Assert class provides various methods for making assertions in our tests. In this case, we are using the Equal method to assert that the expected result of the Sum , Divideand Averagemethods matches the actual result.

We are using the Assert.Throws method to assert that calling the Divide method with a denominator value of 0 should throw a DivideByZeroException. This method takes a delegate (in this case, a lambda expression calling the Divide method) and the expected exception type as arguments. If the Divide method does not throw a DivideByZeroException, the test will fail.

Now let’s test if our CRUD operations are working fine

    public class UserRepositoryTests
{
private readonly IUserRepository _userRepository;
public UserRepositoryTests()
{
DbContextOptions<Context> options;
var builder = new DbContextOptionsBuilder<Context>();
builder.UseInMemoryDatabase("UnitTestDb");
options = builder.Options;
Context context = new Context(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
_userRepository = new UserRepository(context);
}
[Fact]
public void TestAddUser()
{
var user = GetUserObj();
Assert.Empty(_userRepository.GetAll());
_userRepository.Create(user);
Assert.Single(_userRepository.GetAll());
}
[Fact]
public void TestDeleteUser()
{
var user = GetUserObj();
_userRepository.Create(user);
Assert.Single(_userRepository.GetAll());
_userRepository.Delete(user);
Assert.Empty(_userRepository.GetAll());
}
[Fact]
public void TestUpdateUser()
{
var user = GetUserObj();
_userRepository.Create(user);
user.Name= "Uğur Can";
_userRepository.Update(user);
Assert.Equal("Uğur Can", _userRepository.Get(1).Name);
}
[Fact]
public void TestGetAll()
{
var user = GetUserObj();
_userRepository.Create(user);
Assert.Single(_userRepository.GetAll());
}
[Fact]
public void TestGet()
{
var user = GetUserObj();
_userRepository.Create(user);
var userFromDb = _userRepository.Get(1);
Assert.Equivalent(user, userFromDb);
}
private User GetUserObj()
{
return new User()
{
Age = 28,
Email = "ugur.yildirim@avl.com",
Id = 1,
Name = "Uğur",
Surname = "Yıldırım"
};
}
}

In this example, the UserRepositoryTests class contains test methods called TestAddUser , TestDeleteUser, TestUpdateUser,TestGetAll and TestGetthat tests all the crud methods of the IUserRepository interface.

The constructor first uses the UseInMemoryDatabase method provided by the Entity Framework Core in-memory database provider to create an in-memory database and seed it with the expected User object.

Then the tests are calling the methods of the IUserRepository and making the necessary Assertions to see if they are passing or failing.

This is just a simple example, but it illustrates how the UseInMemoryDatabase method can be used with the xUnit testing framework and the repository pattern to test repository methods that interact with a database.

You can access to this project via here.

That’s it for Unit Testing in C#, see you in the next episode :)

--

--