Aracılığıyla paylaş


Birim testlerini düzenleme

Bazen birim testlerinin belirli bir sırada çalıştırılmasını isteyebilirsiniz. İdeal olarak, birim testlerinin hangi sırayla çalıştırıldığı önemli olmamalıdır ve birim testlerinin sıralanmasından kaçınmak en iyi yöntemdir. Ne olursa olsun, bunu yapmanız gerekebilir. Bu durumda, bu makalede test çalıştırmalarının nasıl sıralanması gösterilmektedir.

Not

Test sıralama ve test paralelleştirmesi ayrı endişelerdir. Yürütme sırasının belirtilmesi, testlerin başlama sırasını belirler, ancak paralelleştirme etkinleştirilirse birden çok test eşzamanlı olarak çalışmaya devam edebilir. Testlerin belirtilen sırayla birer birer çalışmasını sağlamak için paralelleştirmeyi de devre dışı bırakmanız gerekir.

Kaynak koda göz atmak isterseniz order .NET Core birim testleri örnek deposuna bakın.

İpucu

Bu makalede açıklanan sıralama özelliklerine ek olarak, alternatif olarak Visual Studio ile özel çalma listeleri oluşturmayı göz önünde bulundurun.

Alfabetik olarak sırala

Not

MSTest, testleri varsayılan olarak bir sınıf içinde sıralı olarak çalıştırır. Paralelliği bir <Parallelize> dosyadaki ayarı kullanarak .runsettings yapılandırıyorsanız, sınıflar arasındaki testler eşzamanlı olarak çalıştırılabilir ve sıralama yalnızca her sınıf içindeki sırayı etkiler.

MSTest, test sınıfında tanımlandıkları sıraya göre testleri bulur.

Test Gezgini'nde (Visual Studio veya Visual Studio Code) çalışırken testler, test adlarına göre alfabetik sırada sıralanır.

Test Gezgini'nin dışında çalıştırılırken testler, test sınıfında tanımlandığı sırayla yürütülür.

Not

Test14 adlı bir test, sayı Test22 değerinden küçük olsa bile 14'den önce çalıştırılacaktır. Test adı sıralaması, testin metin ismini kullandığından bu şekildedir.

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);
    }
}

MSTest 3.6'dan başlayarak, yeni bir runsettings seçeneği hem Test Gezgini'nde hem de komut satırında test adlarına göre testleri çalıştırmanıza olanak tanır. Bu özelliği etkinleştirmek için ayarı runsettings dosyanıza ekleyin OrderTestsByNameInClass :

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>

  <MSTest>
    <OrderTestsByNameInClass>true</OrderTestsByNameInClass>
  </MSTest>

</RunSettings>

xUnit test çerçevesi, test çalıştırma sırasının daha ayrıntılı ve denetlenmesini sağlar. ITestCaseOrderer ve ITestCollectionOrderer arabirimlerini, bir sınıf veya test koleksiyonları için test vakalarının sırasını denetlemek amacıyla uygularsınız.

Not

xUnit, test sınıflarını varsayılan olarak paralel olarak çalıştırır. Tek bir sınıf içindeki testler her zaman sıralı olarak çalıştırılır, bu nedenle ITestCaseOrderer bu sınıf içindeki diziyi denetler. Tüm sınıflarda paralelliği devre dışı bırakmak için, derleme düzeyinde uygulayın, örneğin [assembly: CollectionBehavior(DisableTestParallelization = true)], AssemblyInfo.cs veya test projenizdeki herhangi bir kaynak dosyasında.

Test çalışmasına göre alfabetik sıralama

Test çalışması durumlarını yöntem adlarına göre sıralamak için ITestCaseOrderer öğesini uygularsınız ve bir sıralama mekanizması sağlarsınız.

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);
}

Ardından bir test sınıfında TestCaseOrdererAttribute ile test sırasını ayarlarsınız.

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);
    }
}

Koleksiyona göre alfabetik sıralama

Test koleksiyonlarını görünen adlarına göre sıralamak için ITestCollectionOrderer öğesini uygular ve bir sıralama mekanizması sağlarsınız.

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);
}

Test koleksiyonları potansiyel olarak paralel çalışabileceğinden, CollectionBehaviorAttribute ile koleksiyonların test paralelleştirmesini açıkça devre dışı bırakmanız gerekir. Ardından uygulamasını TestCollectionOrdererAttributeolarak belirtin.

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;
    }
}

Özel özniteliğe göre sıralama

XUnit testlerini özel özniteliklerle sıralamak için öncelikle güvenmeniz gereken bir öznitelik gerekir. Bir TestPriorityAttribute’yi aşağıdakiler gibi tanımlayın.

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;
}

Ardından, aşağıdaki PriorityOrderer arabirimi uygulamasını ITestCaseOrderer göz önünde bulundurun.

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());
}

Ardından bir test sınıfında TestCaseOrdererAttribute ile PriorityOrderer test vakası sırasını belirlersiniz.

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);
    }
}

Önceliğe göre sırala

Not

NUnit, testleri varsayılan olarak tek bir iş parçacığı içinde sıralı olarak çalıştırır. Öznitelikleri uygulamadığınız [Parallelizable] sürece, [Order] öznitelik yalnızca belirtilen dizide seri yürütmeyi garanti etmek için yeterlidir.

Testleri açıkça sıralamak için, NUnit bir OrderAttributesağlar. Bu özniteliğe sahip testler, bu özniteliğe sahip olmayan testlerden önce başlatılır. Sipariş değeri, birim testlerini çalıştırma sırasını belirlemek için kullanılır.

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);
    }
}

Sonraki Adımlar