Xunit custom traits for categories

In xunit you able to use [Trait("Category", "Sample")] for your tests, and here is how you can simplify things a little bit:

using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
using XunitCategoriesSample.Traits;

namespace XunitCategoriesSample.Traits
{
    public class CategoryDiscoverer : ITraitDiscoverer
    {
        public const string KEY = "Category";

        public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
        {
            var ctorArgs = traitAttribute.GetConstructorArguments().ToList();
            yield return new KeyValuePair<string, string>(KEY, ctorArgs[0].ToString());
        }
    }

    //NOTICE: Take a note that you must provide appropriate namespace here
    [TraitDiscoverer("XunitCategoriesSample.Traits.CategoryDiscoverer", "XunitCategoriesSample")]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class CategoryAttribute : Attribute, ITraitAttribute
    {
        public CategoryAttribute(string category) { }
    }
}

namespace XunitCategoriesSample
{
    public class Class1
    {
        [Fact]
        [Category("Jobsearcher")]
        public void PassingTest()
        {
            Assert.Equal(4, Add(2, 2));
        }

        [Fact]
        [Category("Employer")]
        public void FailingTest()
        {
            Assert.Equal(5, Add(2, 2));
        }

        int Add(int x, int y)
        {
            return x + y;
        }
    }
}

NOTICE you must provide right namespaces in TraitDiscoverer attribute.

But here is more, lets make even more specialized attributes:

public class JobsearcherTraitDiscoverer : ITraitDiscoverer
{
    public const string VALUE = "Jobsearcher";

    public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
    {
        yield return new KeyValuePair<string, string>(CategoryDiscoverer.KEY, VALUE);
    }
}

[TraitDiscoverer("XunitCategoriesSample.Traits.JobsearcherTraitDiscoverer", "XunitCategoriesSample")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class JobsearcherTraitAttribute : Attribute, ITraitAttribute
{
    public JobsearcherTraitAttribute()
    {
    }
}

So from now on you will be able to just type [JobsearcherTrait]

Links:

https://github.com/xunit/xunit/issues/394 - discussion about why TraitAttribute was marked as sealed

https://github.com/xunit/samples.xunit/tree/master/TraitExtensibility - sample by xunit how to make custom attributes

https://github.com/wespday/CategoryTraits.Xunit2 - one more sample

https://github.com/xunit/xunit/blob/47fdc2669ae6aa28f6d642e202840193dfc7dbd7/test/test.xunit.execution/Common/TraitHelperTests.cs - xunit test sample of implementing custom attributes