allure-framework/allure-csharp

Base class XUnit Allure attributes are not applied when child class has attributes

mingazhev opened this issue · 0 comments

I'm submitting a ...

  • bug report
  • feature request

What is the current behavior?

There are 2 test classes, one inherits from another:

[AllureLabel("layer", "unit")]
public class BaseTest
{
// Test methods
}

[AllureStory("User registration")]
public class UserRegistrationTests : BaseTest
{
// Test methods
}

When test methods are executed, there is only "story" label in "labels" in results JSON:

"labels": [
    // Other labels
    {
      "name": "story",
      "value": "User registration"
    }
  ],

However, if I remove "AllureStory" like the following:

[AllureLabel("layer", "unit")]
public class BaseTest
{
// Test methods
}

public class UserRegistrationTests : BaseTest
{
// Test methods
}

resulting JSON will have the property from the base BaseTest class I need:

"labels": [
    // Other labels
    {
      "name": "layer",
      "value": "unit"
    }
  ],

What is the expected behavior?

I want all the attributes from the base classes to be added to Allure report

What is the motivation / use case for changing the behavior?

It is convenient to have a base class for the service to provide common Allure information for the whole service or project, such as:

  • layer
  • service name
  • component
    without the need to copy them everywhere.

Environment:

  • Allure version: 2.10-SNAPSHOT
  • Test framework: XUnit

Other information

This behaviour exists because of a, bit strange, logic inside XUnits GetCustomAttributes method:

        internal static IEnumerable<IAttributeInfo> GetCustomAttributes(Type type, Type attributeType, AttributeUsageAttribute attributeUsage)
        {
            IEnumerable<IAttributeInfo> results = Enumerable.Empty<IAttributeInfo>();

            if (type != null)
            {
                List<ReflectionAttributeInfo> list = null;
                foreach (CustomAttributeData attr in type.GetTypeInfo().CustomAttributes)
                {
                    if (attributeType.GetTypeInfo().IsAssignableFrom(attr.AttributeType.GetTypeInfo()))
                    {
                        if (list == null)
                            list = new List<ReflectionAttributeInfo>();

                        list.Add(new ReflectionAttributeInfo(attr));
                    }
                }

                if (list != null)
                    list.Sort((left, right) => string.Compare(left.AttributeData.AttributeType.Name, right.AttributeData.AttributeType.Name, StringComparison.Ordinal));

                results = list ?? Enumerable.Empty<IAttributeInfo>();

                if (attributeUsage.Inherited && (attributeUsage.AllowMultiple || list == null))
                    results = results.Concat(GetCustomAttributes(type.GetTypeInfo().BaseType, attributeType, attributeUsage));
            }

            return results;
        }

It seems that it gets attributes from the base class only if there are no attributes in current one