# Exploring Custom Attributes in AutoFixture and xUnit

Writing setup code for unit tests can be a cumbersome activity. Especially in legacy codebases where many tests may be missing, or unreliable, or when the unit being tested is larger than it would be given sufficient time and resources to refactor it apart. When tackling poor-quality software, one good first step can be to solidify the behaviour with tests, to open the door to refactoring with confidence. In this scenario, it is crucial the maintenance of those tests does not cost as much or more than that of the original code.

AutoFixture is an excellent library for obliterating almost all of the typical setup code when writing unit tests. A colleague, who seemed to enjoy writing unit tests a little too much, introduced me to it. It did not take long for the team to begin converting every legacy test the team touched to using it.

This article will not go into general usage of AutoFixture, [Mark Seemen](https://blog.ploeh.dk/tags/#AutoFixture-ref) and others have covered it comprehensively. What this article aims to provide is a way to combine the declarative [SUT factory](https://blog.ploeh.dk/2009/02/13/SUTFactory/) approach e.g.

```csharp
[Theory, AutoData]
public void IntroductoryTest(int expectedNumber, MyClass sut)
{
    int result = sut.Echo(expectedNumber);
    Assert.Equal(expectedNumber, result);
}
```

With some of the shared setup benefits and convenience that we get from the basic usage.

```csharp
public class BasicUsageTest
{
    private readonly IFixture _fixture = FixtureFactory.Create();

    public BasicUsageTest()
    {
        _fixture.Customize<int>(c => c.FromFactory(() => 9));
    }

    [Fact]
    public void Create__UsesSetup()
    {
        _fixture.Create<int>().ShouldBe(9);
        _fixture.Create<int>().ShouldBe(9);
        _fixture.Create<int>().ShouldBe(9);
    }
}
```

You could use custom attributes with a variety of customizations, although it feels like a lot of overhead when all we want is some shared fixture setup for a particular test class.

Instead, taking inspiration from NUnit's [SetUp](https://docs.nunit.org/articles/nunit/writing-tests/attributes/setup.html) attribute we can define a few new attributes to serve a similar purpose for setting up the fixture.

We begin with a `SetupFixtureAttribute` to mark the setup method we want to define within our test classes. There is a little extra fluff in here to silence some warnings that we are on top of. We use the `MeansImplicitUse` attribute, which comes from [JetBrains.Annotations](https://www.nuget.org/packages/JetBrains.Annotations/), since the setup methods will be called later via reflection. We also handle [xUnit1013](https://xunit.net/xunit.analyzers/rules/xUnit1013) as suggested by xUnit's documentation.

```csharp
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Method)]
[IgnoreXunitAnalyzersRule1013]
public class SetupFixtureAttribute : Attribute { }

// https://xunit.net/xunit.analyzers/rules/xUnit1013
public sealed class IgnoreXunitAnalyzersRule1013Attribute : Attribute
{
}
```

Unfortunately, we cannot easily extend the built-in `AutoDataAttribute` from AutoFixture for this particular use case so we need to replace it with our own. It is a little large to embed nicely into this article, so instead find the `SetupAutoDataAttribute` linked, with examples, [here](https://github.com/MichaelNel/AutoFixture.Samples/blob/main/AutoFixture.Attributes.Tests/Attributes/SetupAutoDataAttribute.cs). The public interface is kept the same as the `AutoDataAttribute` so you can easily add additional attributes with whatever customizations are desired.

Then an attribute can be declared as it would have with AutoFixture's [AutoDataAttribute](https://blog.ploeh.dk/2010/10/08/AutoDataTheorieswithAutoFixture/), only now with the `SetupAutoDataAttribute` we have defined.

```csharp
public class AutoDomainDataAttribute : SetupAutoDataAttribute
{
    public AutoDomainDataAttribute() : base(FixtureFactory.Create)
    {
    }
}
```

With `FixtureFactory.Create`, a static class with any default fixture setup necessary between tests.

Finally, we can bring all of our new attributes together in a test class.

```csharp
public class AutoDomainDataAttributeTest
{
    [SetupFixture]
    public static void SetupFixture(IFixture fixture)
    {
        fixture.Customize<int>(c => c.FromFactory(() => 2));
    }

    [Theory]
    [AutoDomainData]
    public void SetupFixture__AppliesCustomizations(int a, int b, int c)
    {
        a.ShouldBe(2);
        b.ShouldBe(2);
        c.ShouldBe(2);
    }
}
```

With this arrangement, we get the elegance of the `AutoData` attribute with the power of the basic usage even for complex setup code. When combined with AutoFixture's existing integration points we have the flexibility of:

1. Customizations on parameters by deriving from `CustomAttribute`.
    
2. Customizations on individual tests by deriving from `SetupAutoDataAttribute`.
    
3. Customizations on tests in a class by using the `SetupFixture` attribute in test classes.
    
4. Global customizations by using a static fixture factory.
    

```csharp
public class CompleteCustomizationsTest
{
    [SetupFixture]
    public static void SetupFixture(IFixture fixture)
    {
        fixture.Customize(new MyLongCustomization());
    }

    /// <summary>
    ///     1. Double customization from custom parameter attribute.
    ///     2. Int customization from custom SetupAutoDataAttribute.
    ///     3. Long customization from SetupFixture marked method.
    ///     4. String customization from static fixture factory.
    /// </summary>
    [Theory]
    [IntCustomizedAutoDomainData]
    public void Test([DoubleCustomize] double myDouble, int myInt, long myLong, string myString)
    {
        myDouble.ShouldBe(1.1);
        myInt.ShouldBe(100);
        myLong.ShouldBe(200);
        myString.ShouldBe("bananas");
    }
}
```

That is a tonne of flexibility. You can find complete working examples along with all the attributes described in this article on [GitHub](https://github.com/MichaelNel/AutoFixture.Samples/tree/main). There is also the [inline data](https://github.com/MichaelNel/AutoFixture.Samples/blob/main/AutoFixture.Attributes.Tests/InlineAutoDomainDataAttributeTest.cs) equivelant for conventional xUnit parameterised tests.

Writing highly testable code reduces the need for such complex setup scenarios but when you do face them, this arrangement can minimize the friction. If you have any comments or suggestions I encourage you to leave a comment below. I am interested in other approaches that are more harmonious with AutoFixture and xUnit's existing patterns.
