You write Unit Tests wrong.
Tags: csharp, dotnet, xunit, autofixture
Published: 2023-11-04 20:11:53

Every one of us writes unit tests. Because it is a de facto standard of development. You tend to use a set of packages for testing, such as xUnit, FluentAssertation, Bogus, and Moq. In this article, I want to show you the Swiss knife of Unit testing. Today, we'll speak about AutoFixture. It's a very powerful tool for unit testing for everyday routines. And most mainly, it allows you to write less code in the Arrange block. Let's demonstrate it in practice. I created a base test project from a template where was already installed a bunch of packages needed for running unit tests with the xUnit library. To use AutoFixture, you need to install this package.

To start using it, you should create AutoFixture in your test class.

```C#
private readonly IFixture _fixture;
public SampleTests()
{
    _fixture = new Fixture();
}
```
The AutoFixture uses the generic Create<T> method. It creates random data, and you no longer need manual fill except for specific values. In the first example, I show how to make primitive data. 

```C#
[Fact]
public void WhenEmployeeInstanceCreated_ThenCreatedValidInstance()
{
    //Arrange
    var name = _fixture.Create<string>();
    var surname = _fixture.Create<string>();
    var age = _fixture.Create<int>();
    var position = _fixture.Create<string>();
    var rate = _fixture.Create<decimal>();

    //Act
    var employee = new Employee(name, surname, age, position, rate);

    //Assert
    employee.Name.Should().Be(name);
    employee.Surname.Should().Be(surname);
    employee.Age.Should().Be(age);
    employee.Position.Should().Be(position);
    employee.Rate.Should().Be(rate);
}
```
However, this test can be improved. But you need to install an additional package, `AutoFixture.Xunit2`. As you can see, the Arrange block was deleted.

```C#
[Theory, AutoData]
public void WhenEmployeeInstanceCreatedWithAutoData_ThenCreatedValidInstance(
    string name, string surname, int age, string position, decimal rate)
{
    // Act
    var employee = new Employee(name, surname, age, position, rate);
    // Assert
    employee.Name.Should().Be(name);
    employee.Surname.Should().Be(surname);
    employee.Age.Should().Be(age);
    employee.Position.Should().Be(position);
    employee.Rate.Should().Be(rate);
}
```

The AutoFixture can work with classes and also generate data for each property.

```C#
[Fact]
public void WhenAddNewEmployee_ThenAddedOneEmployee()
{
    // Arrange
    var employee = _fixture.Create<Employee>();
    var company = _fixture.Create<Company>();
    var employeesCount = company.Employees.Count;
    // Act
    company.AddEmployee(employee);
    // Assert
    company.Employees.Count.Should().Be(employeesCount + 1);
}
```

Sure, you can manage it, and you can set specific data for specific properties. We also can create collections of items. Let's do it.

```C#
[Fact]
public void WhenRemoveEmployee_ThenRemovedEmployee()
{
    // Arrange
    var employees = _fixture.CreateMany<Employee>(5).ToList();
    var company = _fixture.Build<Company>()
        .With(x => x.Employees, employees)
        .Create();
    // Act
    company.RemoveEmployee(employees.First());
    // Assert
    company.Employees.Count.Should().Be(4);
}
```

We also can ignore specific properties if needed.

```C#
[Fact]
public void WhenAddNewEmployee_CreatedInstanceWithAutoProperties()
{
    // Arrange
    var employee = _fixture.Build<Employee>()
        .OmitAutoProperties()
        .Create();
    var employees = _fixture.Build<Employee>()
        .OmitAutoProperties()
        .CreateMany(5)
        .ToList();
    var company = _fixture.Build<Company>()
        .With(x => x.Employees, employees)
        .Without(x => x.City)
        .Create();
    // Act
    company.AddEmployee(employee);
    // Assert
    company.Employees.Count.Should().Be(6);
    company.City.Should().Be(null);
}
```

Let's consider another example that also allows ignore properties. If you set `OmitAutoProperties`, it means that filled be only auto properties. The rest properties will be NULL.

```C#
[Theory, AutoData]
public void GetEmployee_WhenSpecificNameAndSurname_ThenEmployeeIsReturned(
    string name, string surname)
{
    // Arrange
    var employees = _fixture.Build<Employee>()
        .OmitAutoProperties()
        .With(x => x.Name, name)
        .With(x => x.Surname, surname)
        .CreateMany(1)
        .ToList();
    var department = _fixture.Build<Company>()
        .With(x => x.Employees, employees)
        .Create();
    // Act
    var employee = department.GetEmployee(name);
    // Assert 
    employee.Should().NotBeNull();
    employee?.Name.Should().Be(name);
    employee?.Email.Should().Be(null);
}
```

We considered too simple tests, but most tests have moq services. And AutoFixture also works with it. If you prefer the Moq package, then you need to install the package `AutoFixture.AutoMoq`. The AutoFixture uses the Moq library that was integrated for work with AutoFixture. However, you need to add some configuration for using it. Modify AutoFixture initialization.

```C#
_fixture = new Fixture()
            .Customize(new AutoMoqCustomization()
            {
                ConfigureMembers = true
            });
```

The Moq uses as usual.

```C#
[Theory, AutoData]
public void CalculateSalary_ThenValidInstanceIsReturnedMoq(string name)
{
    // Act
    var payrollService = new Mock<IPayrollService>();
    var employee = _fixture.Create<Employee>();
    payrollService.Setup(x => x.GetSalary(employee)).Returns(1000);
    var company = new Company(name, payrollService.Object);
    var salary = company.GetSalary(employee);
    // Assert
    salary.Should().Be(1000);
}
```

If you are used to it, use NSubstitute. Sure, you also can add it. Just install the `AutoFixture.AutoNSubstitute` package and add another configuration.

```C#
_fixture = new Fixture()
            .Customize(new AutoMoqCustomization()
            {
                ConfigureMembers = true
            }).Customize(new AutoNSubstituteCustomization()
            {
                ConfigureMembers = true
            })
```

Using the NSubstitute is also as usual.

```C#
[Theory, AutoData]
public void CalculateSalary_ThenValidInstanceIsReturnedNSubstitute(string name)
{
    // Arrange
    var payrollService = Substitute.For<IPayrollService>();
    var employee = _fixture.Create<Employee>();
    payrollService.GetSalary(employee).Returns(1000);
    
    // Act
    var company = new Company(name, payrollService);
    var salary = company.GetSalary(employee);
    
    // Assert
    salary.Should().Be(1000);
}
```

If you like to use FakeItEasy, then I also have good news for you. If you install the `AutoFixture.AutoFakeItEasy` package and set the configuration, you can generate fake data. 

```C#
_fixture = new Fixture()
            .Customize(new AutoMoqCustomization()
            {
                ConfigureMembers = true
            }).Customize(new AutoNSubstituteCustomization()
            {
                ConfigureMembers = true
            }).Customize(new AutoFakeItEasyCustomization()
            {
                ConfigureMembers = true
            });
```

If you are used to Bogus, unfortunately, the AutoFixture does not support it.

```C#
[Fact]
public void WhenEmployeeInstanceCreatedFake_ThenCreatedValidInstance()
{
    //Arrange
    var employee = A.Fake<Employee>();
    var company = A.Fake<Company>();
    //Act
    company.AddEmployee(employee);
    var currentEmployee = company.Employees.Single();
    //Assert

    currentEmployee.Name.Should().Be(employee.Name);
    currentEmployee.Surname.Should().Be(employee.Surname);
    currentEmployee.Age.Should().Be(employee.Age);
    currentEmployee.Position.Should().Be(employee.Position);
    currentEmployee.Rate.Should().Be(employee.Rate);
}
```

In conclusion, AutoFixture can help you reduce the code count and minimize hardcoded data. Also, AutoFixture significantly simplifies writing unit tests, making them more readable and clean.
I hope this information was helpful to you, and I wish you always green tests and, sure, happy coding.

The source code is [here](https://github.com/SergKorol/AutoFixtureSample).

<a href="https://www.buymeacoffee.com/b9z99kntvtQ" target="_blank"><img src="http://dartfordwaffler.co.uk/wp-content/uploads/2021/03/buy-me-a-beer.jpg" alt="Buy Me A Beer" style="height: 60px !important;width: 317px !important;" ></a>