I started using xUnit.Net a few weeks ago. My first question was how to do the things I was used to do in other testing frameworks like MSTest or NUnit, especially when using this framework for unit testing and for higher level tests like Selenium RC web tests. Here’s how I went about it.

This is the second, out of three posts on this subject.

>In my previous post I showed an example about converting a MSTest class to xUnit.Net and now I want to provide a solution for converting the MSTest TestCategory attribute to an equivalent implementation in xUnit.Net.

MSTest allowed us to run the test that belongs to a specific category. Let’s see how this can be accomplished in xUnit.Net.

using Xunit;
using Xunit.Extensions;

namespace xUnitCustomizations
{
    [CustomTestClassCommand]
    public class TestClass
    {
        [Fact, TestCategory("Unit")]
        public void FastTest()
        {
            Debug.WriteLine("fast test executed");
            Assert.True(true);
        }

        [Fact, TestCategory("Integration")]
        public void SlowTest()
        {
            Thread.Sleep(5000);
            Debug.WriteLine("slow test executed");
            Assert.True(true);
        }
    }
}

CustomTestClassCommandAttribute attribute is used to indicate that a custom test runner will be used.

public class CustomTestClassCommandAttribute : RunWithAttribute
{
    public CustomTestClassCommandAttribute() : base(typeof(CustomTestClassCommand)) { }
}

CustomTestClassCommand is the class that implements ITestClassCommand and acts as the runner for the test fixture, note that this approach is runner independent which means we will not require changing xUnit console or GUI.

public class CustomTestClassCommand : ITestClassCommand
{
    // Delegate most of the work to the existing TestClassCommand class so that we
    // can preserve any existing behavior (like supporting IUseFixture).
    readonly TestClassCommand cmd = new TestClassCommand();

    #region ITestClassCommand Members
    public object ObjectUnderTest
    {
        get { return cmd.ObjectUnderTest; }
    }

    public ITypeInfo TypeUnderTest
    {
        get { return cmd.TypeUnderTest; }
        set { cmd.TypeUnderTest = value; }
    }

    public int ChooseNextTest(ICollection testsLeftToRun)
    {
        return cmd.ChooseNextTest(testsLeftToRun);
    }

    public Exception ClassFinish()
    {
        return cmd.ClassFinish();
    }

    public Exception ClassStart()
    {
        return cmd.ClassStart();
    }

    public IEnumerable EnumerateTestCommands(IMethodInfo testMethod)
    {
        return cmd.EnumerateTestCommands(testMethod);
    }

    public bool IsTestMethod(IMethodInfo testMethod)
    {
        return cmd.IsTestMethod(testMethod);
    }

    public IEnumerable EnumerateTestMethods()
    {
        string category;

        foreach (IMethodInfo method in cmd.EnumerateTestMethods())
        {
            category = string.Empty;
            foreach (IAttributeInfo attr in method.GetCustomAttributes(typeof(TestCategoryAttribute)))
                category = attr.GetPropertyValue("Value");

            if (category.ToLower().Contains("unit")) // We can make this configurable
                yield return method;
        }
    }
    #endregion
}

The Method public IEnumerable EnumerateTestMethods() filters the tests methods by TestCategory attribute value. Note that we can make this configurable to make CI server to run unit test as soon as there are changes in the repository. This provides quick feedback and schedules the execution of slower tests like integration or Web UI test.

In my next post I will show how to create a Custom RunAfterTestFailed attribute to run a method whenever a test fails.