【问题标题】:Synchronize multiple unit test assemblies同步多个单元测试程序集
【发布时间】:2019-07-03 19:28:33
【问题描述】:

我有 CommonUnitTestSemaphoreLocker 类的程序集:

public static class UnitTestSemaphoreLocker
{
    private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1);

    public static void Lock([NotNull] Action work)
    {
        if (work == null) throw new ArgumentNullException(nameof(work));

        Semaphore.Wait();
        try
        {
            work();
        }
        finally
        {
            Semaphore.Release();
        }
    }

    public static async Task LockAsync([NotNull] Func<Task> worker)
    {
        if(worker == null) throw new ArgumentNullException(nameof(worker));

        await Semaphore.WaitAsync();
        try
        {
            await worker();
        }
        finally
        {
            Semaphore.Release();
        }
    }
}

我有两个单元测试程序集,比如说TestAssemblyATestAssemblyB

来自两个程序集的单元测试使用一种资源,每次仅支持一次调用。 所以我希望你使用我的UnitTestSemaphoreLocker 来锁定单元测试并让它们一个一个地执行:

[TestMethod]
public void ConstructionTest()
{
    UnitTestSemaphoreLocker.Lock(() =>
    {
       //test body
    });
}

它非常适合在一个程序集中进行测试,但似乎其中两个创建了我的常见静态 UnitTestSemaphoreLocker 类的自己的实例。

有没有办法从两个程序集中同步单元测试?同时部分必须使用async/await

【问题讨论】:

  • 你的单元测试应该被隔离。这对我来说是一种代码味道。如果您必须在单元测试中这样做,那么您的代码是错误的,应该重构。
  • @Liam 是的,我完全同意你的看法。但它的遗留项目,遗憾的是这不能改变。我们有一些外部资源,供两个测试程序集使用。我希望我们可以模拟它,但在现实生活中,我们不能再投入几周时间来重构 2000 多个单元测试中的复杂代码。

标签: c# unit-testing async-await synchronization mstest


【解决方案1】:

根据观察到的行为,Visual Studio 测试运行程序 (VSTest) 并行执行多个测试程序集。它启动多个进程(每个 CPU 内核最多一个)。每个这样的进程都包含它自己的 CLR 副本,每个都加载一些 AppDomain,当然还有一个单独的测试程序集实例。

所有这一切都意味着静态成员不共享,并且由于 SemaphoreSlim 依赖于 CLR 同步原语,同步也无法跨多个 CLR 实例工作。

我能想到两种可能的解决方案:

方案一:跨进程同步

SemaphoreSlim 替换为Semaphore。后者可以初始化为机器范围的命名信号量,允许多个进程在由字符串名称标识的同一信号量实例上同步。见an example here。另请参阅Semaphore and SemaphoreSlim 了解更多信息。

如果只有少数测试需要同步,这可能是一个很好的解决方案。但是,如果必须同步大部分或所有测试,则运行并行测试流程毫无意义——请参阅解决方案 #2。

解决方案 2:禁用并行测试进程

您可以通过.runsettings 文件中的&lt;MaxCpuCount&gt; 元素控制并行进程的数量。将其值设置为 1 应该禁用并行进程:

<RunSettings>
  <RunConfiguration>
    <MaxCpuCount>1</MaxCpuCount>
  </RunConfiguration>
</RunSettings>

更多详情请见Configure unit tests by using a .runsettings file

这并不是说您不能并行化您的测试。 MSTest 有一个名为“in-assembly parallel test execution” (IAP) 的功能,可以通过包含以下程序集级属性(通常在 AssemblyInfo.cs 中)来启用它:

[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]

与生成进程的 VSTest 运行程序相比,IAP 生成多个线程,所有线程都共享同一个 AppDomain。在这种情况下,静态成员只有一个副本,并且基于 CLR 的与SemaphoreSlim 的同步也可以正常工作。

这篇文章中有关 IAP 的更多信息:MSTest V2: in-assembly parallel test execution

【讨论】:

    猜你喜欢
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多