52

I have written the xUnit test cases in C#. That test class contains so many methods. I need to run the whole test cases in a sequence. How can I set the test case sequence in xUnit?

wonea
  • 4,783
  • 17
  • 86
  • 139
Pankaj Saha
  • 869
  • 3
  • 17
  • 37
  • 7
    Why do you care about the order in which the tests are executed? It's generally a bad idea for tests to depend on each other in any way - they should be independent of each other. – Jon Skeet Feb 09 '12 at 11:47
  • 54
    While that is indeed true for unit tests that isn't the case for integration tests. – David Brower Mar 14 '16 at 15:25
  • 5
    In case someone is wondering how to do this as of 2020: you can use https://github.com/asherber/Xunit.Priority (available on NuGet). – Cesar Jul 15 '20 at 12:12
  • @Cesar - Thanks for the hint, I'll try it. On NUGET I found also `Xunit.Extensions.Ordering`, but I haven't tried that out (yet) - I think that it orders everything alphabetically. – Matt Jan 28 '21 at 14:06
  • 1
    Note that with XUnit.Priority you can define a [DefaultPriority(x)] on class level and a [Priority(y)] on method (Fact) level. And tests with the same priority run in alphabetical order - so it might be sufficient to set a default priority on class level and name the tests alphabetically. – Matt Jan 28 '21 at 14:22

5 Answers5

54

In xUnit 2.* this can be achieved using the TestCaseOrderer attribute to designate an ordering strategy, which can be used to reference an attribute that is annotated on each test to denote an order.

For example:

Ordering Strategy

[assembly: CollectionBehavior(DisableTestParallelization = true)] 

public class PriorityOrderer : ITestCaseOrderer
{
    public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
    {
        var sortedMethods = new SortedDictionary<int, List<TTestCase>>();

        foreach (TTestCase testCase in testCases)
        {
            int priority = 0;

            foreach (IAttributeInfo attr in testCase.TestMethod.Method.GetCustomAttributes((typeof(TestPriorityAttribute).AssemblyQualifiedName)))
                priority = attr.GetNamedArgument<int>("Priority");

            GetOrCreate(sortedMethods, priority).Add(testCase);
        }

        foreach (var list in sortedMethods.Keys.Select(priority => sortedMethods[priority]))
        {
            list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
            foreach (TTestCase testCase in list)
                yield return testCase;
        }
    }

    static TValue GetOrCreate<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TKey key) where TValue : new()
    {
        TValue result;

        if (dictionary.TryGetValue(key, out result)) return result;

        result = new TValue();
        dictionary[key] = result;

        return result;
    }
}

Attribute

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestPriorityAttribute : Attribute
{
    public TestPriorityAttribute(int priority)
    {
        Priority = priority;
    }

    public int Priority { get; private set; }
}

Test Cases

[TestCaseOrderer("FullNameOfOrderStrategyHere", "OrderStrategyAssemblyName")]
public class PriorityOrderExamples
{
    [Fact, TestPriority(5)]
    public void Test3()
    {
        // called third
    }

    [Fact, TestPriority(0)]
    public void Test2()
    {
      // called second
    }

    [Fact, TestPriority(-5)]
    public void Test1()
    {
       // called first
    }

}

xUnit 2.* ordering samples here

KnowHoper
  • 4,352
  • 3
  • 39
  • 54
  • 2
    This worked great only after I added an assembly attribute... [assembly: CollectionBehavior(DisableTestParallelization = true)] – RyanOC Feb 19 '19 at 20:54
  • 1
    Thanks! This may be required since I wrote that answer. – KnowHoper Feb 19 '19 at 23:21
  • 1
    An "official" example of this can be found [here](https://github.com/xunit/samples.xunit/tree/master/TestOrderExamples/TestCaseOrdering). And it's not necessary to use attributes to accomplish this, conventions like alphabetical ordering by method names etc might be used as well. – Anders May 05 '20 at 11:25
  • Strange, but none of that worked for me. I created 4 EF integration tests, and despite alphabetical ordering and applying Priority it didn't regard the right order. It was always running them in order 4-1-2-3 and I named them Test_01, Test_02, Test_03 and Test_04. The order is important because I used it for CRUD-Testing (create, read, update, delete). – Matt Jan 28 '21 at 14:31
  • Note this only works for tests in the same *class* (not collection unfortunately). See https://github.com/xunit/xunit/issues/2217 for a write up. – Avner May 05 '22 at 23:46
25

Testpriority: at the bottom of this page.

[PrioritizedFixture]
public class MyTests
{
    [Fact, TestPriority(1)]
    public void FirstTest()
    {
        // Test code here is always run first
    }
    [Fact, TestPriority(2)]
    public void SeccondTest()
    {
        // Test code here is run second
    }
}

BTW, I have the same problem right now. And yes, it is not the clean art.. but QA wanted a manual test.. so an automated test with a specific order already is a big leap for them.. (cough) and yes, it is not really unit testing..

wonea
  • 4,783
  • 17
  • 86
  • 139
Andreas Reiff
  • 7,961
  • 10
  • 50
  • 104
  • 1
    TestPriority only works on a per-module/class basis. So different classes are still executed in random order. (C# compiler embeds classes in a non predicable order into assembly.) In order to make the testing sequence (testers have a test protocol) easier and repeatable, I added alphabetical sorting. So I created a modified version of xunit 1.9 that executes test classes in alphabetical order. Have a look at http://www.andreas-reiff.de/2012/06/xunit-with-alphabetically-sorted-classes-and-proper-display-list-matching-execution-order/ . – Andreas Reiff Jan 22 '13 at 21:13
  • @bricelam, that link seems broken, it goes into some redirect loop. – Sergey Dec 23 '15 at 19:36
17

If you really have the need to prioritize your tests (probably not your unit tests) you can use Xunit.Priority. I have used it for some integration testing and works really well and simple without the overhead of having to write your prioritization classes, for simple case scenarios

MarcolinoPT
  • 551
  • 6
  • 10
0

For some reason, XUnit.Priority didn't work for me. In my test cases, it wasn't running the tests in the priority order specified.

So I tried XUnitPriorityOrderer, which is similar to use but was working (To quickly test it, save the following code in a text editor as OrderedXUnitTests.linq, then open it with LinqPad 6 and execute it. Alternatively, you can also copy the TestClass to Visual Studio and add XUnit, XUnit.Runner.VisualStudio and XUnitPriorityOrderer):

<Query Kind="Program">
  <NuGetReference>XUnitPriorityOrderer</NuGetReference>
  <Namespace>Xunit</Namespace>
  <Namespace>XUnitPriorityOrderer</Namespace>
</Query>


#load "xunit"

// using XUnitPriorityOrderer
// see: https://github.com/frederic-prusse/XUnitPriorityOrderer
void Main()
{
    RunTests();  // Call RunTests() or press Alt+Shift+T to initiate testing.
}


#region private::Tests

[TestCaseOrderer(CasePriorityOrderer.TypeName, CasePriorityOrderer.AssembyName)]
public class TestClass
{
    static List<string> Order { get; set; }
    
    public TestClass()
    {
        Order = Order ?? new List<string>();
    }

    [Fact, Order(2)]
    void Test_Xunit_AnotherTest()
    {
        Order.Add("Test_Xunit_AnotherTest");
        Assert.True(3 + 1 == 4);
    }

    [Fact, Order(1)]
    void Test_Xunit()
    {
        Order.Add("Test_XUnit");
        Assert.True(1 + 1 == 2);
    }

    [Fact, Order(99)]
    void Print_Order()
    {
        Order.Add("Print_Order");
        var strOrder = string.Join(", ", Order.ToArray());
        strOrder.Dump("Execution Order");
        Assert.True(true);
    }
}
#endregion

This will run the tests in given order (Order(1), Order(2) and then Order(99)) and will dump the executed tests finally (test method Print_Order()).

Matt
  • 25,467
  • 18
  • 120
  • 187
-4

You can't, by design. It's deliberately random in order to prevent anyone getting one of those either by desire or by accident.

The randomness is only for a given Test class, so you may be able to achieve your goals by wrapping items you want to control the order of inside a nested class - but in that case, you'll still end up with random order whenever you have more than two Test Methods in a class.

If you're trying to manage the building up of fixtures or context, the built-in IUseFixture<T> mechanism may be appropriate. See the xUnit Cheat Sheet for examples.

But you really need to tell us more about what you're trying to do or we'll just have to get speculative.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249