Today, testing is one of the most important aspects of the development and production of software. Although writing a test reduces the speed of development, its benefits are evident during development, the addition of new features, and changes. If you use test writing in your projects and change part of the code, you do not have to worry about another part of the task failing or changing its behavior because it is specified in the tests that are written. In this article, we want to write some test examples with the xUnit library. 

Consider a service that receives data from a repository and must perform a series of processes on it. In this article, our goal is to test the relevant service, not a repository, which means we want to write a test for the output of the service.
Consider the UserService class, which has a method called AverageUsersAge that displays the average age of users.

public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }
    public async Task<int> AverageUsersAge()
    {
        int result = 0;
        var people = await _userRepository.GetAllUsers();
        if (people is null)
            return result;

        result = (int)people.Select(a => a.Age).DefaultIfEmpty().Average();
        return result;
    }
}

It is first checked that if the data received from the repository is null, it returns a value of 0. Otherwise, it must return the average age of the users. Now if we want to write for this test method, we must do the following.
First, create a xUnit Test Project .Net Core project and install the following packages.

  • FluentAssertions
  • Moq
  • xunit
  • xunit.runner.visualstudio

You can also use the following configuration to install the required packages:

<ItemGroup>
  <PackageReference Include="FluentAssertions" Version="6.2.0" />
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
  <PackageReference Include="Moq" Version="4.16.1" />
  <PackageReference Include="xunit" Version="2.4.1" />
  <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"/>
</ItemGroup>

Then we create a class called UserServiceTest in the test project.

public class UserServiceTest
{
    private readonly IUserService _userService;
    private readonly Mock<IUserRepository> _userRepository;
    public UserServiceTest()
    {
        _userRepository = new Mock<IUserRepository>();
        _userService = new UserService(_userRepository.Object);
    }
}

In the constructor of the UserTestService class, the _userService field is prototyped and receives a Mock<IUserRepository> input. But the input of the UserService class receives an instance of IUserRepository, not Mock<IUserRepository>. Using the Mock library, we can send a Fake object to the service so that we do not receive an error during prototyping. We can then mock the methods used by the Repository within the UserService class. That is, we can simulate the output of Repository methods and write our own tests based on it.
For example, in the following test, we specify that if the output of the GetAllUsers method for IUserRepository is null, the value zero should be returned:

[Fact]
public async Task AverageUsersAge_When_Repository_Return_Null_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync((List<User>)null);

    var result = await _userService.AverageUsersAge();

    result.Should().Be(0);
}

Now if you debug the test and debug the AverageUsersAge method, the null value will be returned when the GetAllUsers method arrives. In the example below, the output of the GetAllUsers method is tested if it is Empty:

[Fact]
public async Task AverageUsersAge_When_Repository_Return_Empty_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(new List<User>());

    var result = await _userService.AverageUsersAge();

    result.Should().Be(0);
}

In the example below, we have considered a class for fake data and checked that if three records with specified values are received from the repository, the average age of the users should be calculated equal to the value.

[Fact]
public async Task AverageUsersAge_When_Repository_Return_List_Of_Users_Then_Average_Of_Age_Should_Be_Retunred()
{

    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(UserMockData.People);

    var result = await _userService.AverageUsersAge();

    var expected = (UserMockData.AdultUser.Age + UserMockData.ChildUser.Age + UserMockData.InfantUser.Age) / 3;

    result.Should().Be(expected);
}

UserMockData class:

public static class UserMockData
 {
     public static List<User> People
     {
         get
         {
             return new List<User>
             {
                 AdultUser,
                 ChildUser,
                 InfantUser
             };
         }
     }
     public static User AdultUser
     {
         get
         {
             return new User
             {
                 Age = 55
             };
         }
     }
     public static User ChildUser
     {
         get
         {
             return new User
             {
                 Age = 10
             };
         }
     }
     public static User InfantUser
     {
         get
         {
             return new User
             {
                 Age = 2
             };
         }
     }
 }

This way we can test for your services that depend on a repository or other service.

;)

Powered by Froala Editor

Comments