C# 在MSTest中,如何指定某些测试方法不能彼此并行运行?

C# 在MSTest中,如何指定某些测试方法不能彼此并行运行?,c#,.net,mstest,C#,.net,Mstest,我有一套大型的集成测试来测试网站服务器。大多数测试可以并行运行。但是,我有一些更改设置的方法,它们在并行运行时可能会导致彼此失败 作为一个简化的例子,假设我进行了以下测试: TestPrice_5PercentTax TestPrice_10PercentTax TestPrice_NoTax TestInventory_Add10Items TestInventory_Remove10Items 库存测试不会相互妨碍,也不会受到价格测试的影响。但是价格测试将改变Tax设置,因此如果5和10同

我有一套大型的集成测试来测试网站服务器。大多数测试可以并行运行。但是,我有一些更改设置的方法,它们在并行运行时可能会导致彼此失败

作为一个简化的例子,假设我进行了以下测试:

TestPrice_5PercentTax
TestPrice_10PercentTax
TestPrice_NoTax
TestInventory_Add10Items
TestInventory_Remove10Items
库存测试不会相互妨碍,也不会受到价格测试的影响。但是价格测试将改变
Tax
设置,因此如果
5
10
同时运行,
10
可能在
5
完成之前改变设置,
5
将失败,因为它看到的是10%的税,而不是预期的5%


我想为这三个价格测试定义一个类别,并说它们可能不会同时运行。它们可以与任何其他测试同时运行,但不能与其他价格测试同时运行。在MSTest中是否有这样做的方法?

MSTest v2的功能如下

[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]
// Notice the assembly bracket, this can be compatible or incompatible with how your code is built

namespace UnitTestProject1
{
    [TestClass]
    public class TestClass1
    {
        [TestMethod]
        [DoNotParallelize] // This test will not be run in parallel
        public void TestPrice_5PercentTax() => //YourTestHere?;

        [TestMethod]
        [DoNotParallelize] // This test will not be run in parallel
        public void TestPrice_10PercentTax() => //YourTestHere?;            

        [TestMethod]
        [DoNotParallelize] // This test will not be run in parallel
        public void TestPrice_NoTax() => //YourTestHere?;

        [TestMethod]
        public void TestInventory_Add10Items() => //YourTestHere?;

        [TestMethod]
        public void TestInventory_Remove10Items() => //YourTestHere?;
    }
}
更详细的信息可以在这里找到


我强烈建议您至少快速阅读链接,因为这可能会帮助您解决和理解并行或顺序运行测试的问题。

我想提供一个我开始但没有追求的潜在解决方案

首先,我创建了一个类,可以将其用作测试方法的属性

[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple =true)]
public class NoParallel : Attribute
{
    public NoParallel(string nonParallelGroupName)
    {
        SetName = nonParallelGroupName;
    }

    public string SetName { get; }
}
然后,我把它添加到我的测试方法中,这将产生冲突

[NoParallel("Tax")]
public void TestPrice_5PercentTax();

[NoParallel("Tax")]
public void TestPrice_10PercentTax();

[NoParallel("Tax")]
public void TestPrice_NoTax();

// This test doesn't care
public void TestInventory_Add10Items();

// This test doesn't care
public void TestInventory_Remove10Items();
我给了我的测试类一个静态的互斥体字典,它由互斥体的名字组成

private static Dictionary<string, Mutex> exclusiveCategories = new Dictionary<string, Mutex>();

我们决定不继续这样做,因为这真的不值得付出努力。最终,我们决定将无法一起运行的测试拉到它们自己的测试类中,并按照H.N的建议用
[DoNotParallelize]
标记它们。

创建一个测试方法,并在其中调用冲突测试,而不是从MSTest调用。这对我来说不是一个理想的解决方案,因为如果
TestPrice5percenttax
失败,其余的测试将不会运行。我不想在其中一个中断时丢失关于其余部分的信息。根据您启动MSTest的方式,最简单的解决方案可能是添加一个类似@DourHighArch的子句。或者通过使用您正在使用的测试框架中可能找到的工具,将特定测试拆分为单独运行。或者使用方法调用与并行性冲突的指定测试。根据初始化的执行方式,使用单独的任务/方法运行指定的测试。我只在buildserver环境中遇到过与VsTest相同的问题,因此我的评论对于这个特定的解决方案可能不准确。这是否回答了您的问题?这并不像我希望的那样可定制,但我想我正在寻找MSTest无法提供的东西。我最终使用了这个解决方案。谢谢很乐意帮助:)大多数事情都可以实现,但正如您在解决方案回复中所述。更高级的方法通常需要更多的时间来进行测试。
public static List<string> NonparallelSets(this TestContext context, ContextHandler testInstance)
{
    var result = new List<string>();

    var testName = context.TestName;
    var testClassType = testInstance.GetType();
    var testMethod = testClassType.GetMethod(testName);

    if (testMethod != null)
    {
        var nonParallelGroup = testMethod.GetCustomAttribute<NoParallel>(true);

        if (nonParallelGroup != null)
        {
            result = nonParallelGroups.Select(x => x.SetName).ToList();
        }
    }

    result.Sort();
    return result;
}
[TestInitialize]
public void PerformSetup()
{
    // Get all "NoParallel" strings on the test method currently being run
    var nonParallelSets = testContext.NonparallelSets(this);

    // A test can have multiple "NoParallel" attributes so do this for all of them
    foreach (var setName in nonParallelSets)
    {
        // If this NoParallel set doesn't have a mutex yet, make one
        Mutex mutex;
        if (exclusiveCategories.ContainsKey(setName))
        {
            mutex = exclusiveCategories[setName];
        }
        else
        {
            mutex = new System.Threading.Mutex();
            exclusiveCategories[setName] = mutex;
        }

        // Wait for the mutex before you can run the test
        mutex.WaitOne();
    }
}

[TestCleanup]
public void PerformTeardown()
{
    // Get the "NoParallel" strings on the test method again
    var nonParallelSets = testContext.NonparallelSets(this);

    // Release the mutex held for each one
    foreach (var setName in nonParallelSets)
    {
        var mutex = exclusiveCategories[setName];
        mutex.ReleaseMutex();
    }
}