AutoFixture - Specimen Builders
Tags: dotnet, testing, unittest
Published: 2023-09-12 21:44:00


I will try to keep this one short by not going into details of what [Autofixture](https://github.com/AutoFixture/AutoFixture#overview) is , why we need it... I am assuming you would be familiar with it

**What is a specimen ?**

In programming we work with types(i.e. `int`, `string`, `decimal`, etc. ) -  _**a specimen is an example value of a particular type**_.

E.g. "Kanelbulle" is a specimen (an example value) for the type string or 0.23m , 0.50m are specimens for the type decimal.

**What is a specimen builder in context Auto fixture ?**

Having known what a specimen is now, we can safely assume that the logic ( basically set of instructions) to build a specific specimen is a specimen builder. 

In terms of AutoFixture, it is a concrete implementation of the [ISpecimenBuilder](https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/Kernel/ISpecimenBuilder.cs)

Given a complex type like this

```
class Employee
{
 public string Name { get; set; }
 public int Code{ get; set; }
}

```
when we ask the fixture (`fixture.Create<Employee>()`) to give us anonymous data of type Employee, behind the scenes a set of specimen builders (either default or custom) are going to run and generate us a specimen for a string and int (_which are basically the two properties of the Employee class here_).

 For e.g. the default specimen builder for a string spits out a guid as the value for us. For a complex type , like Employee in this case, a string gets a specimen prepended with the property name (as it is the case for all the properties of a complex type) something like this _Namead6fb2f0-d23a-4bb0-a083-8ffca9a139aa_

Before moving to writing a custom (concrete) implementation of the `ISpecimenBuilder`, I want to put across the way I have understood the AutoFixture pipeline (feel free to correct me here)

1. AutoFixture is responsible for creating Anonymous data for a particular type of `T` (** _anonymous data is anything which is not going to affect our SUT /system under test in anyway i.e. we don't care for the values but the instance or type is needed by our SUT regardless of its value_)
2. T could be a primitive type or any custom defined type
3. When creating an instance (anonymous data) of `T`, the first step is the customization phase where the AutoFixture library looks for a collection of the ISpecimenBuilders
4. AutoFixture has its own set of default Specimen Builders and then if we write any custom ones,they will override those default specimen builders if registered in this phase
5.The customization phase is taken care by calling the `Customizations` or the `Customize ` on the `fixture` (we will see in a bit) instance
6. The next step in the pipeline is then to "run" these concrete specimen builders to generate the specimen (example values) for a given type
7. Last is the fall back step, where the Autofixture library applies fallbacks/defaults (tries real hard to generate a specimen for us !) and if still no specimen was able to be generated for a particular type(could be because of some validations in the constructor in case of a complex type), then eventually throw an error .

> In nut shell , a request for fixture.Create<T>() would go through a series of specimen builders to finally give us an instance of T

**When would you want to create a custom specimen builder ?**

If you want to influence the logic of building one in any specific way !

For e.g. 

```
var fixture = new Fixture();

var date1 = fixture.Create<DateTime>();
```

The default specimen builder for `DateTime `shipped with Autofixture is going to return you a specimen (value) of a random date time value per your system's culture but say you want to override this and instead want the UTC date to be returned as a specimen

In this case you can have your own specimen builder implementation. Refer [this](https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/CurrentDateTimeGenerator.cs) and you can build your UTC one in a similar way

```
 public class CurrentUtcDateTimeGenerator : ISpecimenBuilder
    {
        
        public object Create(object request, ISpecimenContext context)
        {
            if (!typeof(DateTime).Equals(request))
            {
                return new NoSpecimen();
            }

            return DateTime.UtcNow;
        }
    }
```

and then register this specimen builder (remember the Customize stage which we spoke about earlier ?) 

`fixture.Customizations.Add(new CurrentUtcDateTimeGenerator());`

next whenever we ask for an instance of type DateTime from this fixture it is going to give us the current UTC date

A lot more things can be achieved through writing your own specimen builders.
For e.g. say you have a class

` public class Employee
 {
  public string Name { get; set; }
  public string EmployeeCode { get; set; }
 }`

You want to influence how EmployeeCode is generated , then you could override the default guid specimen for a string here.


```
 public class EmployeeCodeGenerator : ISpecimenBuilder
 {

  private readonly char[] _allowedChars = { 'V', 'I', 'D', 'S', 'H', 'A' };

  public object Create(object request, ISpecimenContext context)
  {

   //we use reflection here and pattern matching to see if the specimen we are trying to build is a property
   //we are interested in the EmployeeCode property of the Employee class

   if (request is PropertyInfo propertyInfo)
   {

    //next we match the name to influence the specimen building logic for the EmployeeCode property

    if (propertyInfo.Name.Contains("employeecode", StringComparison.InvariantCultureIgnoreCase))
    {
     //when we get hold of it we return our custom 3 digit code instead

     return new string(_allowedChars, 0, 3);

    }

   }

   return new NoSpecimen();
  }
 }

```
and then use the above like this

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

var employee = fixture.Create<Employee>();
Assert.Equal(3, employee.EmployeeCode.Length);
```

Hope this was useful

Reference

[Convention-based Customizations with AutoFixture](https://blog.ploeh.dk/2010/10/19/Convention-basedCustomizationswithAutoFixture/)