# Supercharging Your Test Data With AutoFixture

> A walkthrough of how to use AutoFixture to generate test data and how it can help you write better tests.

- URL: https://blog.nimblepros.com/blogs/supercharging-your-test-data-with-autofixture/
- Author: [Kyle McMaster](https://blog.nimblepros.com/authors/kyle/)
- Published: 2023-12-01
- Series: [Testing Techniques](https://blog.nimblepros.com/series/testing-techniques/)
- Categories: [Software Development](https://blog.nimblepros.com/categories/software-development/)
- Publisher: [NimblePros](https://blog.nimblepros.com/)

---

*This article is part of a series on leveling up your testing skills*
- [Creating Test Objects via Design Patterns](https://blog.nimblepros.com/blogs/creating-test-objects-via-design-patterns/)
- [Supercharging Your Test Data With AutoFixture](https://blog.nimblepros.com/blogs/supercharging-your-test-data-with-autofixture/)
- [Creating Domain-Driven Test Data With Bogus](https://blog.nimblepros.com/blogs/creating-domain-driven-test-data-with-bogus)
- [Boosting the Builder Pattern Using Bogus](https://blog.nimblepros.com/blogs/boosting-the-builder-pattern-using-bogus)

AutoFixture is a library for .NET that can help you generate data for your tests. It can reduce the amount of code needed to Arrange (the first A in [the `Arrange-Act-Assert` style of testing](https://deviq.com/testing/arrange-act-assert)) your tests while also making them more robust. There are also extensions for many common testing libraries to make it even more friendly and productive with the testing framework of your choice. In this post, we'll look at how to use AutoFixture to generate test data and how it can help you write better tests.

## Getting started with AutoFixture

To get started with AutoFixture, you'll need to install the [AutoFixture NuGet package](https://www.nuget.org/packages/AutoFixture/). You can do this from the command line with the following command.

```bash
dotnet add package AutoFixture
```

Once you have the package installed, you can immediately start using AutoFixture in your tests. The following snippet generates a string value using the default behavior which will provide a value equivalent to `Guid.NewGuid().ToString();`.

```csharp
var fixture = new Fixture();
string value = fixture.Create<string>();
```

Easy, right? Let's dive a bit deeper!

## Using AutoFixture for More Complex Arrangements

Now that we've seen how to get started, let's iterate an existing XUnit test and see a few ways we can simplify it with AutoFixture. The example test is a modified version of the `CreateContributorHandler` tests found in the [Ardalis.CleanArchitecture Repository](https://github.com/ardalis/CleanArchitecture/blob/main/tests/Clean.Architecture.UnitTests/UseCases/Contributors/CreateContributorHandlerHandle.cs). The `CreateContributorCommand` is a class that contains the properties needed to create a new `Contributor` and inherits from the `ICommand<T>` interface from the [Ardalis.SharedKernel](https://github.com/ardalis/Ardalis.SharedKernel/blob/main/src/Ardalis.SharedKernel/ICommand.cs) NuGet library.

```csharp
public record CreateContributorCommand(
  string Email,
  string FirstName,
  string LastName,
  int Followers,
  int Following,
  int Stars,
  string Status)
  : Ardalis.SharedKernel.ICommand<Result<int>>;
```

The following test Arranges the data by creating an instance of a `CreateContributorCommand`. It Acts by executing the  `Handle` method on `CreateContributorCommandHandler`. Then, it Asserts the result is successful.

```csharp
[Fact]
public async void ShouldCreateContributorGivenValidValues()
{
  string email = "JohnDoe@Microsoft.com";
  string firstName = "John";
  string lastName = "Doe";
  int followers = 40;
  int following = 20;
  int stars = 179;
  var command = new CreateContributorCommand(
      email: email,
      firstName: firstName,
      lastName: lastName,
      followers: followers,
      following: following,
      stars: stars,
      status: ContributorStatus.NotSet.Name);

  var result = await _handler.Handle(command, CancellationToken.None);

  result.IsSuccess.Should().BeTrue();
}
```

Notice that this test has a lot of code in the Arrange step relative to the rest of the test. While this isn't a huge problem on its own, tests with more complex or nested entities can become difficult to read and maintain. AutoFixture can help in this scenario by generating the `CreateContributorCommand` without requiring us to creatively think of test data for every field. In this way, it acts as a [Factory or Builder](https://blog.nimblepros.com/blogs/creating-test-objects-via-design-patterns/) for our classes. A `Fixture` can be initialized to generate a `CreateContributorCommand`.

```csharp
[Fact]
public void ShouldCreateContributorGivenValidValues()
{
  var fixture = new Fixture();
  var command = fixture.Create<CreateContributorCommand>();

  var result = await _handler.Handle(command, CancellationToken.None);

  result.IsSuccess.Should().BeTrue();
}
```

This will generate a `CreateContributorCommand` with values similar to the following:

```json
{
  "Id": "64432aec-6f04-499f-b36e-83491cb9f2e4",
  "Email": "Email3d8cd253-1a6d-44b8-beec-3f3f76b5435f",
  "FirstName": "FirstNamedb1cbf15-908d-49ff-a040-e4c38b751ad3",
  "LastName": "LastName80d5c493-7b93-4e14-8384-89249c4b6c1b",
  "Followers": 1,
  "Following": 2,
  "Stars": 3,
  "Status": "Statusb288fc4c-9f35-463b-b23a-1eac6ac34bf6"
}
```

This introductory example uses a `Fixture` with all of the default behaviors. For example, string properties will be generated with values that have the format "{PropertyName}{Guid.NewGuid()}". If we want to provide a value that is better suited for the Email property, we can use the `Build`, `With`, `Create` convention to pass a value to the `Fixture` in a test method as shown below.

```csharp
var command = fixture.Build<CreateContributorCommand>()
  .With(c => c.Email, "JohnDoe@Microsoft.com")
  .Create();
```

```json
{
  "Id": "64432aec-6f04-499f-b36e-83491cb9f2e4",
  "Email": "JohnDoe@Microsoft.com",
  "FirstName": "FirstNamedb1cbf15-908d-49ff-a040-e4c38b751ad3",
  "LastName": "LastName80d5c493-7b93-4e14-8384-89249c4b6c1b",
  "Followers": 1,
  "Following": 2,
  "Stars": 3,
  "Status": "Statusb288fc4c-9f35-463b-b23a-1eac6ac34bf6"
}
```

## Customizing AutoFixture For Your Domain

By default, AutoFixture can generate data for many types without any customization. In the context of DDD however, we may want to tell AutoFixture how to speak our ubiquitous language. In this case, you can customize the `Fixture` to generate data for your use cases. Let's expand the previous example so that the `Contributor` class has a string `Status` property. The `Status` property should only have the values "CoreTeam", "Community", or "NotSet" and might be implemented as a [SmartEnum](https://ardalis.com/enum-alternatives-in-c/). If we simply run the test with a default `Fixture`, we'll get a value like "Status1d671c38-0290-4ec4-9b2c-cc1b3bb477ce" which is not valid for our application's domain. To fix this, we can customize the `Fixture` to generate a valid `Status` value using an `ISpecimenBuilder`. Specimen Builders are used by AutoFixture to define how to generate data for specific types. They are often required for types that AutoFixture cannot generate by default or for data that needs to be generated in a specific way. AutoFixture's documentation describes the interface as "Builds, or partakes in building, anonymous variables (specimens)." with the remark that "The request can be any object, but will often be a System.Type or other System.Reflection.MemberInfo instances.".

```csharp
public class ContributorStatusNotSetGenerator : ISpecimenBuilder
{
  public object Create(object request, ISpecimenContext context)
  {
    var props = request as PropertyInfo;

    if (props is null)
    {
      return new NoSpecimen();
    }

    if (props.PropertyType != typeof(string) || props.Name != "Status")
    {
      return new NoSpecimen();
    }

    return ContributorStatus.NotSet.Name;
  }
}
```

`ContributorStatusNotSetGenerator` can then be added to any `Fixture` instance using the `Add` method on the `Customizations` collection. Note that this simple customization will only generate a value of "NotSet" but could easily be extended to generate a random valid ContributorStatus value if necessary.

```csharp
var fixture = new Fixture();
fixture.Customizations.Add(new ContributorStatusNotSetGenerator());
```

Depending on the context of your tests, it may make sense to consistently have a specific set of values for certain sets of tests. This technique can be particularly useful when multiple `Customizations` are combined in a single `Fixture`. For example, we could create a shared "Domain Fixture" which contains the customization created above and other common customizations that are used across common test scenarios. This can be done by creating a class that inherits from `Fixture` and adding the customizations in the constructor. 

```csharp
public class YourDomainSpecificFixture : Fixture
{
  public YourDomainSpecificFixture()
  {
      Customizations.Add(new ContributorStatusNotSetGenerator());
      // Other potential customizations for your domain like a ContributorEmailGenerator, etc.
  }
}
```

## AutoFixture and XUnit 

One final feature of AutoFixture that I'd like to highlight that can further reduce the amount of code needed to arrange your tests is the `AutoDataAttribute` available in the `AutoFixture.Xunit2` NuGet package. This attribute can be used with your custom fixtures to automatically generate test data for your tests without instantiating a `Fixture` in the test class or test method. We can create our domain-specific attribute `YourDomainDataAttirubute` that inherits from `AutoDataAttribute` and uses the `YourDomainSpecificFixture` we created above.

```csharp
public class YourDomainDataAttribute : AutoDataAttribute
{
  public YourDomainDataAttribute() 
      : base(() => new YourDomainSpecificFixture())
  {
  }
}
```

Now that we have an attribute that combines our custom `Fixture` with the `AutoDataAttribute`, we can use it in our tests by simply making our test method a `Theory` and making a parameter for `CreateContributorCommand`. The `AutoDataAttribute` will automatically generate a `CreateContributorCommand` and pass it to the test method.

```csharp
[Theory, YourDomainData]
public async void ShouldCreateContributorGivenValidValues(CreateContributorCommand command)
{
  var result = await _handler.Handle(command, CancellationToken.None);

  result.IsSuccess.Should().BeTrue();
}
```

In this iteration, our test method is much simpler than the original example. We no longer need to create a `Fixture` or manually create a `CreateContributorCommand`. The Arrange step has automagically disappeared compared to the initial version of the test allowing us to focus on the intent and meaning behind it without being obstructed by the set of the test data.

## Conclusion

Hopefully, this post has given you a glimpse of some of the features of `Autofixture` and its ecosystem of packages that can be used to reduce boilerplate Arrange code in your tests. A lot of these practices can go a long way when combined with other testing patterns like the Builder pattern. If you're interested in learning more about AutoFixture, I'd recommend checking out the [AutoFixture documentation](https://github.com/AutoFixture/AutoFixture). All the code from this example can be found in the repository linked below.

## References

- [Sample Code](https://github.com/KyleMcMaster/AutoFixtureSamples/blob/main/tests/Clean.Architecture.UnitTests/UseCases/Contributors/CreateContributorHandlerHandle.cs)
- [AutoFixture](https://github.com/AutoFixture/AutoFixture)
- [Mark Seeman's Blog](https://blog.ploeh.dk/tags/#AutoFixture-ref)
- [Creating Test Objects via Design Patterns](https://blog.nimblepros.com/blogs/creating-test-objects-via-design-patterns/)
