Writing Unit and integration tests are generally composed of setting up relevant test data, carrying the actual execution of the test, and finally making assertions. All this can be summarised as the AAA syntax. That is, Arrange, Act, and Assert.
With AutoFixture, it can significantly save you time by taking away the tedious part of stubbing and arranging test data.
The best way to describe this is to show a traditional test example followed by how it can be replaced with AutoFixture.
A Regular Test
Let's start with a traditional test. In the example below, it demonstrates setting up a customer with fake dummy data. Then the CustomerService
is used to save this customer to some data store. This may be a contrived example, but it demonstrates how much time it can take to stub fake data such as this.
Also, note that a Customer
in this example has an Address
which is another entity that needs to be stubbed.
Libraries do exist to assist in generating fake data such as Bogus. But still one has to write a few lines of code.
public class CustomerTests
{
[Fact]
public void AddCustomer_When_valid_customer_should_save_successfully()
{
// arrange
var customer = new Customer
{
FirstName = "Paula",
LastName = "McKinney",
EmailAddress = "paula_mckinney@fakeemail.org",
DateOfBirth = DateTime.UtcNow.AddYears(-30),
Address =
new Address {
AddressLine1 = "4989 Wayside Lane",
AddressLine2 = "Hayward",
ZipOrPostcode = "94541",
Country = "United States"
}
};
// act
var customerService = new CustomerService();
customerService.AddCustomer(customer);
// assert
// make assertions here.
}
}
Using Autofixture
Let's take the example above and replace it with AutoFixture. To start using AutoFixture, simply add the nuget package
via package manager in Visual Studio
Install-Package AutoFixture
via dotnet CLI
dotnet add package AutoFixture
[Fact]
public void AddCustomer_When_valid_customer_should_save_successfully_with_autofixture()
{
// arrange
var fixture = new Fixture();
var customer = fixture.Create<Customer>();
// act
var customerService = new CustomerService();
customerService.AddCustomer(customer);
// assert
// make assertions here.
}
Hopefully, you can see that it just takes two lines of code from AutoFixture. Wait. What!? For real? Yes, for real. Just two lines of code. Here are the two lines again:
var fixture = new Fixture();
var customer = fixture.Create<Customer>();
AutoFixture does all the work and just to prove it, here's a screenshot of debugging the test and inspecting the customer
object.
You will see that AutoFixture has pre-populated all the fields with dummy data. It has also taken the initiative of stubbing the Address
entity as well.
Autofixture Customisations
What if we want to control some of the behaviour of AutoFixture? Take, for example, the customer's date of birth. What if we wanted to set a specific date of birth for the customer as I may want to test some business logic around the date of birth?
To achieve this, you can use the With
method to override a particular property.
var fixture = new Fixture();
var customer = fixture.Build<Customer>()
.With(c => c.DateOfBirth, DateTime.UtcNow.AddYears(-30))
.Create();
This will set the DateOfBirth
to 10 years in the past.
You can also ignore or disable some properties that you do not want AutoFixture to populate. For instance, the example below will ignore the Address
property.
var customer = fixture.Build<Customer>()
.Without(c => c.Address)
.Create();
Using AutoData
You can take it one step further and use the AutoData
attribute.
Be sure to add the nuget package.
via package manager in Visual Studio
Install-Package AutoFixture.Xunit2
via dotnet CLI
dotnet add package AutoFixture.Xunit2
XUnit example
[Theory, AutoData]
public void AddCustomer_When_valid_customer_should_save_successfully_with_autofixture(Customer customer)
{
// act
var customerService = new CustomerService();
customerService.AddCustomer(customer);
// assert
// make assertions here.
}
NUnit example
[Test, AutoData]
public void AddCustomer_When_valid_customer_should_save_successfully_with_autofixture(Customer customer)
{
// act
var customerService = new CustomerService();
customerService.AddCustomer(customer);
// assert
// make assertions here.
}
As you can see from both XUnit and NUnit examples above, the Customer
is passed as a parameter in the method. There was no need to use the var fixture = new Fixture();
as you have seen from the earlier examples.
This way of testing can be very useful, as well as saving considerable amount of time coding stub and fake data.
Summary
As you can see, with the introduction of AutoFixture, it can significantly reduce writing test data for the arrangement part of tests and also reduce the amount of code. With less code, less maintenance.
For further examples, checkout AutoFixture's cheat sheet and also the AutoFixture GitHub page.
Top comments (1)
You can also use AutoBogus and Bogus together to make a 1-liner. No manual rules necessary: