Darren Oakey
Darren Oakey

Reputation: 3654

can I combine Trait and Fact in xunit?

I really want to categorise some xunit tests as integration tests - but this:

[Fact]
[Trait("integration", "whatever")]

It is not ok with me. What I want to say is

[FactIntegration]

But I can't figure out a way to define a custom attribute that is like two attributes. Is there a way of doing this?

Upvotes: 1

Views: 65

Answers (1)

Michał Turczyn
Michał Turczyn

Reputation: 37470

It is actually pretty simple.

If you want to extend some class' functionality, you are very likely to inherit from it.

TraitAttribute is sealed, so it can't be inherited, so we can always go and see what the class does and try to replicate with custom code (not perfect, when the code is complex, but let's see).

Code for FactAttribute

[XunitTestCaseDiscoverer("Xunit.Sdk.FactDiscoverer", "xunit.execution.{Platform}")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class FactAttribute : Attribute
{
    public virtual string DisplayName { get; set; }
    public virtual string Skip { get; set; }
    public virtual int Timeout { get; set; }
}

Code for TraitAttribute

[TraitDiscoverer("Xunit.Sdk.TraitDiscoverer", "xunit.core")]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public sealed class TraitAttribute : Attribute, ITraitAttribute
{
    public TraitAttribute(string name, string value) { }
}

As we can see, there are not much code going on in those classes.

In order to "inherit" TraitAttribute functionalities, it's enough to inherit ITraitAttribute interface, define appropeiate attributes and define constructor with two string params (name and value). Since we are inheriting interface for TraitAttribute, we are (luckily!) free to just inherit FactAttribute, since it is not sealed, and be done with our new attribute for tests:

[XunitTestCaseDiscoverer("Xunit.Sdk.FactDiscoverer", "xunit.execution.{Platform}")]
[TraitDiscoverer("Xunit.Sdk.TraitDiscoverer", "xunit.core")]
public class FactTraitAttribute(string name, string value) : FactAttribute, ITraitAttribute
{
}

Then you can have your specific attributes, such as FactIntegration:

public class FactIntegrationAttribute : FactTraitAttribute
{
    public FactIntegrationAttribute() : base("integration", "whatever") { }
}

Upvotes: 2

Related Questions