Solicitar testes de unidade
Ocasionalmente, talvez você queira que os testes de unidade sejam executados em uma ordem específica. Idealmente, a ordem na qual os testes de unidade são executados não deve importar e é uma prática recomendada evitar a ordenação de testes de unidade. Independentemente disso, pode haver a necessidade de fazê-lo. Nesse caso, este artigo demonstra como ordenar execuções de teste.
Se você preferir procurar o código-fonte, consulte o repositório de exemplo Ordenar testes de unidade do .NET Core.
Dica
Além dos recursos de ordenação descritos neste artigo, considere a criação de playlists personalizadas com o Visual Studio como alternativa.
Ordem alfabética
O MSTest descobre testes na mesma ordem em que são definidos na classe de teste.
Ao executar por meio do Gerenciador de Testes (no Visual Studio ou no Visual Studio Code), os testes são ordenados em ordem alfabética com base no nome.
Ao executar fora do Gerenciador de Testes, os testes são executados na ordem em que são definidos na classe de teste.
Observação
Um teste chamado Test14
será executado antes do Test2
mesmo que o número 2
seja menor que 14
. Isso ocorre porque a ordenação de nome de teste usa o nome do texto do teste.
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MSTest.Project;
[TestClass]
public class ByAlphabeticalOrder
{
public static bool Test1Called;
public static bool Test2Called;
public static bool Test3Called;
[TestMethod]
public void Test2()
{
Test2Called = true;
Assert.IsTrue(Test1Called);
Assert.IsFalse(Test3Called);
}
[TestMethod]
public void Test1()
{
Test1Called = true;
Assert.IsFalse(Test2Called);
Assert.IsFalse(Test3Called);
}
[TestMethod]
public void Test3()
{
Test3Called = true;
Assert.IsTrue(Test1Called);
Assert.IsTrue(Test2Called);
}
}
A estrutura de teste xUnit permite mais granularidade e controle da ordem de execução do teste. Você implementa as interfaces ITestCaseOrderer
e ITestCollectionOrderer
para controlar a ordem dos casos de teste para uma classe ou coleções de teste.
Ordem por caso de teste em ordem alfabética
Para ordenar casos de teste pelo nome do método, implemente o ITestCaseOrderer
e forneça um mecanismo de ordenação.
using Xunit.Abstractions;
using Xunit.Sdk;
namespace XUnit.Project.Orderers;
public class AlphabeticalOrderer : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(
IEnumerable<TTestCase> testCases) where TTestCase : ITestCase =>
testCases.OrderBy(testCase => testCase.TestMethod.Method.Name);
}
Em seguida, em uma classe de teste, você define a ordem do caso de teste com o TestCaseOrdererAttribute
.
using Xunit;
namespace XUnit.Project;
[TestCaseOrderer(
ordererTypeName: "XUnit.Project.Orderers.AlphabeticalOrderer",
ordererAssemblyName: "XUnit.Project")]
public class ByAlphabeticalOrder
{
public static bool Test1Called;
public static bool Test2Called;
public static bool Test3Called;
[Fact]
public void Test1()
{
Test1Called = true;
Assert.False(Test2Called);
Assert.False(Test3Called);
}
[Fact]
public void Test2()
{
Test2Called = true;
Assert.True(Test1Called);
Assert.False(Test3Called);
}
[Fact]
public void Test3()
{
Test3Called = true;
Assert.True(Test1Called);
Assert.True(Test2Called);
}
}
Ordem por coleção em ordem alfabética
Para ordenar coleções de teste pelo nome de exibição, implemente o ITestCollectionOrderer
e forneça um mecanismo de ordenação.
using Xunit;
using Xunit.Abstractions;
namespace XUnit.Project.Orderers;
public class DisplayNameOrderer : ITestCollectionOrderer
{
public IEnumerable<ITestCollection> OrderTestCollections(
IEnumerable<ITestCollection> testCollections) =>
testCollections.OrderBy(collection => collection.DisplayName);
}
Como as coleções de teste potencialmente são executadas em paralelo, você deve desabilitar explicitamente a paralelização de teste das coleções com o CollectionBehaviorAttribute
. Em seguida, especifique a implementação para o TestCollectionOrdererAttribute
.
using Xunit;
// Need to turn off test parallelization so we can validate the run order
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: TestCollectionOrderer(
ordererTypeName: "XUnit.Project.Orderers.DisplayNameOrderer",
ordererAssemblyName: "XUnit.Project")]
namespace XUnit.Project;
[Collection("Xzy Test Collection")]
public class TestsInCollection1
{
public static bool Collection1Run;
[Fact]
public static void Test()
{
Assert.True(TestsInCollection2.Collection2Run); // Abc
Assert.True(TestsInCollection3.Collection3Run); // Mno
Assert.False(TestsInCollection1.Collection1Run); // Xyz
Collection1Run = true;
}
}
[Collection("Abc Test Collection")]
public class TestsInCollection2
{
public static bool Collection2Run;
[Fact]
public static void Test()
{
Assert.False(TestsInCollection2.Collection2Run); // Abc
Assert.False(TestsInCollection3.Collection3Run); // Mno
Assert.False(TestsInCollection1.Collection1Run); // Xyz
Collection2Run = true;
}
}
[Collection("Mno Test Collection")]
public class TestsInCollection3
{
public static bool Collection3Run;
[Fact]
public static void Test()
{
Assert.True(TestsInCollection2.Collection2Run); // Abc
Assert.False(TestsInCollection3.Collection3Run); // Mno
Assert.False(TestsInCollection1.Collection1Run); // Xyz
Collection3Run = true;
}
}
Ordem por atributo personalizado
Para ordenar testes xUnit com atributos personalizados, primeiro você precisa de um atributo com o qual contar. Defina um TestPriorityAttribute
da seguinte maneira:
namespace XUnit.Project.Attributes;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestPriorityAttribute : Attribute
{
public int Priority { get; private set; }
public TestPriorityAttribute(int priority) => Priority = priority;
}
Em seguida, considere a implementação PriorityOrderer
a seguir da interface ITestCaseOrderer
.
using Xunit.Abstractions;
using Xunit.Sdk;
using XUnit.Project.Attributes;
namespace XUnit.Project.Orderers;
public class PriorityOrderer : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(
IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
{
string assemblyName = typeof(TestPriorityAttribute).AssemblyQualifiedName!;
var sortedMethods = new SortedDictionary<int, List<TTestCase>>();
foreach (TTestCase testCase in testCases)
{
int priority = testCase.TestMethod.Method
.GetCustomAttributes(assemblyName)
.FirstOrDefault()
?.GetNamedArgument<int>(nameof(TestPriorityAttribute.Priority)) ?? 0;
GetOrCreate(sortedMethods, priority).Add(testCase);
}
foreach (TTestCase testCase in
sortedMethods.Keys.SelectMany(
priority => sortedMethods[priority].OrderBy(
testCase => testCase.TestMethod.Method.Name)))
{
yield return testCase;
}
}
private static TValue GetOrCreate<TKey, TValue>(
IDictionary<TKey, TValue> dictionary, TKey key)
where TKey : struct
where TValue : new() =>
dictionary.TryGetValue(key, out TValue? result)
? result
: (dictionary[key] = new TValue());
}
Então, em uma classe de teste, você define a ordem do caso de teste com o TestCaseOrdererAttribute
para o PriorityOrderer
.
using Xunit;
using XUnit.Project.Attributes;
namespace XUnit.Project;
[TestCaseOrderer(
ordererTypeName: "XUnit.Project.Orderers.PriorityOrderer",
ordererAssemblyName: "XUnit.Project")]
public class ByPriorityOrder
{
public static bool Test1Called;
public static bool Test2ACalled;
public static bool Test2BCalled;
public static bool Test3Called;
[Fact, TestPriority(5)]
public void Test3()
{
Test3Called = true;
Assert.True(Test1Called);
Assert.True(Test2ACalled);
Assert.True(Test2BCalled);
}
[Fact, TestPriority(0)]
public void Test2B()
{
Test2BCalled = true;
Assert.True(Test1Called);
Assert.True(Test2ACalled);
Assert.False(Test3Called);
}
[Fact]
public void Test2A()
{
Test2ACalled = true;
Assert.True(Test1Called);
Assert.False(Test2BCalled);
Assert.False(Test3Called);
}
[Fact, TestPriority(-5)]
public void Test1()
{
Test1Called = true;
Assert.False(Test2ACalled);
Assert.False(Test2BCalled);
Assert.False(Test3Called);
}
}
Ordem por prioridade
Para ordenar testes explicitamente, o NUnit fornece um OrderAttribute
. Os testes com esse atributo são iniciados antes dos testes que não o possuem. O valor da ordem é usado para determinar a ordem de execução dos testes de unidade.
using NUnit.Framework;
namespace NUnit.Project;
public class ByOrder
{
public static bool Test1Called;
public static bool Test2ACalled;
public static bool Test2BCalled;
public static bool Test3Called;
[Test, Order(5)]
public void Test1()
{
Test1Called = true;
Assert.That(Test2ACalled, Is.False);
Assert.That(Test2BCalled, Is.True);
Assert.That(Test3Called, Is.True);
}
[Test, Order(0)]
public void Test2B()
{
Test2BCalled = true;
Assert.That(Test1Called, Is.False);
Assert.That(Test2ACalled, Is.False);
Assert.That(Test3Called, Is.True);
}
[Test]
public void Test2A()
{
Test2ACalled = true;
Assert.That(Test1Called, Is.True);
Assert.That(Test2BCalled, Is.True);
Assert.That(Test3Called, Is.True);
}
[Test, Order(-5)]
public void Test3()
{
Test3Called = true;
Assert.That(Test1Called, Is.False);
Assert.That(Test2ACalled, Is.False);
Assert.That(Test2BCalled, Is.False);
}
}