How to use `MemberData` correctly with `Autofixture`?

Viewed 30

I'm writing a .NET application, and I want to use AutoFixture. The class which I'm testing is the following?

internal sealed class AuthenticatedUser : IAuthenticatedUser
{
    private readonly IHttpContextAccessor? httpContextAccessor;

    public AuthenticatedUser(IHttpContextAccessor? httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public IEnumerable<Guid> GetAccessibleSubscriptionGuids()
    {
        return this.httpContextAccessor?.UserRolesForScope(RoleScope.Subscription)
                   .Select(static x => x.ScopeIdentifier)
                   .ToList()
               ?? Array.Empty<Guid>()
                       .AsEnumerable();
    }
}

So, basically this class reads the HttpContext (using the IHttpContextAccessor) interface and based returns a collection of GUID's, based on the data in the HttpContext.

I'm testing this with xUnit. In order to make it work, I have created the following attributes:

[AttributeUsage(AttributeTargets.Method)]
private sealed class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(static () => new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}

[AttributeUsage(AttributeTargets.Method)]
private sealed class AutoMoqMemberDataAttribute : MemberAutoDataAttribute
{
    public AutoMoqMemberDataAttribute(string memberName, params object[] parameters)
        : base(new AutoMoqDataAttribute(), memberName, parameters)
    {
    }
}

These attributes allows me to combine Autofixture with Xunit's MemberData. Now, I want to verify that a set of roles, applied to the HttpContext returns the correct GUID's.

This is the testcase:

public static IEnumerable<object[]> UserRoles =>
    new List<object[]>
    {
        // The user has NO roles.
        new object[] { Array.Empty<UserRole>(), },
        // The user has NO roles with the `Subscription` scope.
        new object[]
        {
            new[]
            {
                new UserRole(Guid.Empty, Role.None),
                new UserRole(Guid.Empty, Role.EnvironmentAdministrator),
                new UserRole(Guid.Empty, Role.TemplateDesigner),
                new UserRole(Guid.Empty, Role.EnvironmentUser),
                new UserRole(Guid.Empty, Role.SupportUser),
            },
        },
    };
[Theory]
[AutoMoqMemberData(nameof(WhenTheHttpContextAccessorIsNotNull.UserRoles))]
internal void ReturnsTheScopeIdentifierOfTheRolesWithTheSubscriptionScope(
    IEnumerable<UserRole> roles,
    [Frozen] Mock<IHttpContextAccessor> httpContextAccessorMock,
    AuthenticatedUser user)
{
    // MOCK SETUP.
    _ = httpContextAccessorMock.SetupGet(static mock => mock.HttpContext)
                               .Returns(
                                    new DefaultHttpContext
                                    {
                                        Items = new Dictionary<object, object?>
                                        {
                                            { "UserRoles", roles },
                                        },
                                    });
    // ASSERT.
    Assert.Empty(user.GetAccessibleEnvironmentGuids());
}

The problem is that, inside the MemberData attribute, I can't use autofixture to generate Guids, or even use AutoFixture to generate the UserRole instances.

Maybe my approach is just wrong. I just discovered the autofixture library, so any help on how to do this properly is highly appreciated.

0 Answers
Related