user6410654
user6410654

Reputation:

C# each attribute should execute the TestMethod

I have created a custom xUnit theory test DataAttribute named RoleAttribute:

public class RoleAttribute : DataAttribute
{
    public Role Role { get; set; }
    public RoleAttribute(Role role, Action<Role> method)
    {
        Role = role;
        AuthRepository.Login(role);
        method(role);
    }

    public override IEnumerable<object[]> GetData(MethodInfo testMethod)
    {
        return new[] { new object[] { Role } };
    }
}

And I have the test method OpenProfilePageTest:

public class ProfileTest : AuthTest
{
    [Theory, Priority(0)]
    [Role(Enums.Role.SuperUser, OpenProfilePageTest)]
    [Role(Enums.Role.Editor, OpenProfilePageTest)]
    public void OpenProfilePageTest(Enums.Role role)
    {
        var profile = GetPage<ProfilePage>();
        profile.GoTo();
        profile.IsAt();
    }
}

What I want is that for each role (attribute) it executes first:

AuthRepository.Login(role); (constructor of RoleAttribute)

and then resumes with the code inside OpenProfilePageTest() method. Before it repeats the same but for the second attribute.

How can I accomplish this, right now I'm trying to accomplish this by passing the OpenProfilePageTest() method inside the attribute and execute it in its constructor. There must be a better way to accomplish this than passing around the method I believe?

Upvotes: 0

Views: 200

Answers (2)

Nkosi
Nkosi

Reputation: 247471

Having an Attribute performing functions other than providing meta data about its adorned member is mixing concerns that cause unnecessary complications and not what it was designed for.

The entire custom attribute can be done away with and the built-in data attributes used instead

For example

public class ProfileTest : AuthTest {
    [Theory, Priority(0)]
    [InlineData(Enums.Role.SuperUser)]
    [InlineData(Enums.Role.Editor)]
    public void OpenProfilePageTest(Enums.Role role) {
        //Arrange
        AuthRepository.Login(role);            
        var profile = GetPage<ProfilePage>();

        //Act
        profile.GoTo();

        //Assert
        profile.IsAt();
    }
}

AuthRepository.Login in this case is part of the setup/arrangement for exercising the desired use case.

Upvotes: 2

hawkstrider
hawkstrider

Reputation: 4341

You can achieve this without passing the method, you need to modify your attribute slightly. I changed the attribute to take all the roles you want to test and return them in the data. Here is an example

public class RolesAttribute : DataAttribute
{
    private Role[] _roles;
    public RolesAttribute(params Role[] roles)
    {
        _roles = roles;
    }

    public override IEnumerable<object[]> GetData(MethodInfo testMethod)
    {
        var data = new List<object[]>();
        //We need to add each role param to the list of object[] params
        //This will call the method for each role
        foreach(var role in _roles)
            data.Add(new object[]{role});
        return data;
    }
}

Then in your test, you just pass all the roles you want to test in a single attribute like so

public class ProfileTest : AuthTest
{
    [Theory, Priority(0)]
    [Roles(Enums.Role.SuperUser, Enums.Role.Editor)]
    public void OpenProfilePageTest(Enums.Role role)
    {
        AuthRepository.Login(role);
        var profile = GetPage<ProfilePage>();
        profile.GoTo();
        profile.IsAt();
    }
}

Upvotes: 2

Related Questions