C# Unit Testing Objects, IEnumerables, and Dates

C# Unit Testing Objects, IEnumerables, and Dates

In a previous post we looked at an introduction to Unit Testing, I want to expand on that and start looking at different data types. To do this I added some additional content to the UserService class.

namespace UnitTesting
{
    public class UserService
    {
        public User GetUserById(int userId)
        {
            return new User { 
                Id = userId, 
                Name = "John Doe", 
                CreationDate = new DateOnly(2024,6,14) };
        }

        public DateOnly GetCreationDate(int userId)
        {
            return new DateOnly(2024,6,14);
        }
    
        public IEnumerable<User> GetUsers()
        {
            return new []
            {
                new User { Id = 1, Name = "John Doe", CreationDate = new DateOnly(2024,6,28) },
                new User { Id = 2, Name = "Jane Doe", CreationDate = new DateOnly(1998,5,14) },
                new User { Id = 3, Name = "John Smith", CreationDate = new DateOnly(1978,8,5) }
            };
        } 
    }

    public class User
    {
        public int Id { get; set; } = 0;
        public string Name { get; set; } = string.Empty;
        public DateOnly? CreationDate { get; set; } = null;
    }
}

Date

Using Fluent Assertions gives us a large number of Test, a complete list can be found here. I have used some of these to test the Creation Date method within the User Service.

[Fact]
public void UserService_GetCreationDate_ReturnDate()
{
    // Arrange
    var userService = new UserService();
    int userId = 1;

    // Act
    var result = userService.GetCreationDate(userId);

    // Assert
    result.Should().NotBe(default);
    result.Should().Be(new DateOnly(2024,6,14));
    result.Should().BeAfter(new DateOnly(2024, 6, 13));
    result.Year.Should().Be(2024);
    result.Month.Should().Be(6);
    result.Day.Should().Be(14);
    result.DayOfWeek.Should().Be(DayOfWeek.Friday);
    result.DayOfYear.Should().Be(166);           
}    

Object

This time were going to test an Object, to do so I’m going to re-use the GetUserById method again. However we need to clean something up first, in each Test Case we New’d up the userService. To keep this cleaner we will create a private member and move the new to the constructor, and then update the already created tests to use the private member.

public class UserServiceTest
{
  private UserService _userService;

  public UserServiceTest()
  {
    _userService = new UserService();
  }

Now we can test the Object, here we have two test;

  • BeofType<TypeName> – Validates that the correct type is returned.
  • BeEquivalentTo – Does a Parity Check between two objects, this validates that all the property values are identical.
[Fact]
public void UserService_GetUserById_ReturnNewUser()
{
    // Arrange
    int userId = 1;

    // Act
    var result = _userService.GetUserById(userId);

    // Assert
    result.Should().BeOfType<User>();
    result.Should().BeEquivalentTo(new User
    {
        Id = userId, 
        Name = "John Doe", 
        CreationDate = new DateOnly(2024,6,14) 
    });
}

IEnumerable

With an IEnumerable we can again check the Type, but we also have content checks to ensure that the contents of the IEnumerable are correct.

[Fact]
public void UserService_GetAllUsers_ReturnAllUsers()
{
    // Arrange

    // Act
    var result = _userService.GetAllUsers();

    // Assert
    result.Should().BeOfType<User[]>();
    result.Should().ContainEquivalentOf(new User
    {
        Id = 1,
        Name = "John Doe",
        CreationDate = new DateOnly(2024, 6, 28)
    });
    result.Should().Contain(x=> x.Id == 2 && x.Name == "Jane Doe");
}