A Guide to Unit Testing Project Setup in .NET
Unit testing is one of most important part of our development process. Because it helps us in :
-
Improving code quality
-
Finding bugs easily
-
It makes refactoring easier and smoother
How can we set up a unit testing project in .NET?
We need to follow these steps :
-
Create test project
-
Add reference
-
Install required nuget packages
-
Write your test and run
1/ Create a unit test project
To ensure compatibility, create a class library project within the same solution as your test project. Ensure the class library targets the same .NET version as the project you’re testing.
For Visual Studio:
-
Right-click on the solution in Solution Explorer
-
Select ‘Add’ -> ‘New Project’
-
Choose a class library project template targeting the same .NET version as your test project.
2/ Add Reference to your test project
Establish a reference to the class library in your test project.
For Visual Studio:
-
Right-click on the test project in Solution Explorer
-
Select ‘Add’ -> ‘Project Reference’
3/ Install Nuget Package
Let’s install the latest versions of the following NuGet packages, as per compatibility with your .NET project version
-
xUnit
-
Microsoft.NET.Test.Sdk
-
xunit.runner.visualstudio
xUnit.net is a free, open-source, community-focused unit testing tool for the .NET Framework and we need other two packages to run our tests.
Microsoft.NET.Test.Sdk handles all necessary under-the-hood stuff for building.NET testing projects.
xunit.runner.visualstudio test explorer runner for the xUnit.net framework
4/ Writing your first unit test
As we have installed the necessary packages, let’s write our first unit test.
public sealed class UserServiceTests
{
private IUsersService _usersService;
public UserServiceTests()
{
_usersService = new UsersService();
}
[Fact]
public void GetUsers()
{
// Arrange
// All those things that need to be passed
// to the method we are going to call
// Arrange mock that when we call that
//specific method, it should return the following result
// Act
// Call the method that we are going to test
var result = _usersService.GetUsers();
// Assert
// Check the result that we got from the method we
//called in the Act section
Assert.NotNull(result);
// Additional assertions can be added to verify the
//result based on expected behavior
}
}
What is Fact Attribute?
[Fact] comes from xUnit.FactAttribute, we need to put this on our methods that work as tests, a necessary convention if we use xUnit for testing.
What is Arrange - Act - Asset Pattern?
AAA is a famous pattern for writing good tests, it properly structures our code.
Arrange says that we need to arrange all the necessary things (e.g., services, interface, properties) to call our desired method.
Secondly, we define our desired mock results in this step as well, suppose we want that when GetUsers is called, we return a specific list of users that we have already defined in our test project. So we arrange that in this step.
The act says to act, call the method, API, page, or whatever we are going to test, and save its result.
In the last step, we check whether the result that came from the second step is our desired one or not so based on that we can pass or fail our test
5/ Mocking with NSubstitute
Before moving forward we need to mock our interfaces instead of creating the service on our own, let’s install one more awesome nuget package.
- NSubstitute
It will help us in mocking the interface and results as well.
public sealed class UserServiceTests
{
private IUsersService _usersServiceMock;
public UserServiceTests()
{
_usersServiceMock = Substitute.For<IUsersService>(); // Via NSubstitute
}
[Fact]
public async Task GetUsers()
{
// Arrange
var users = new List<User>
{
new User { Id = 1, Name = "John Doe", Email = "john.doe@example.com" }
};
// Mock the method to return the list of users
_usersServiceMock.GetUsersAsync().Returns(users); // Via NSubstitute
// Act
var result = await _usersServiceMock.GetUsersAsync(default);
// Assert
Assert.True(result.Count() > 0); // Ensure the result contains users
}
}
Assert on the last line comes from xUnit, but we have one more dedicated package best in assertions.
6/ Better Assertions with FluentAssertions
For this, we need to install FluentAssertions nuget package from the nuget package manager.
This is a toolkit for writing clearer unit tests. It works with popular testing frameworks (MSTest2, NUnit3, XUnit2, MSpec, NSpec3) and allows you to express what you expect your code to do in a more natural way
So after changing the code looks like this :
[Fact]
public async Task GetUsers()
{
// Arrange
var users = new List<User>
{
new User { Id = 1, Name = "John Doe", Email = "john.doe@example.com" }
};
// Mock the service call to return the list of users
_usersServiceMock.GetUsersAsync().Returns(users);
// Act
var result = await _usersServiceMock.GetUsersAsync(default);
// Assert
result.Should().NotBeNull(); // Ensure result is not null
result.Should().HaveCountGreaterThan(0);
// Ensure the result has at least one user
}
7/ How can we call internal resources in our testing library
Unit tests sometimes need to access internal resources within a library( that is being tested), but changing them to the public is not the ideal solution. To address this, we can add the following line of code to the library.
<ItemGroup>
<InternalsVisibleTo Include="Application.UnitTests" />
</ItemGroup>
This line says that internal resources in this library should be visible to Application.UnitTests project.
Whenever you're ready, there are 3 ways I can help you:
- Subscribe to my youtube channel : For in-depth tutorials, coding tips, and industry insights.
- Promote yourself to 9,000+ subscribers : By sponsoring this newsletter
- Patreon community : Get access to all of my blogs and articles at one place