同步多个单元测试程序集
Synchronize multiple unit test assemblies
我有 Common
和 class UnitTestSemaphoreLocker
:
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();
}
}
}
我有两个单元测试程序集,比方说 TestAssemblyA
和 TestAssemblyB
来自两个程序集的单元测试使用一种资源,每次只支持一次调用。
所以我希望你使用我的 UnitTestSemaphoreLocker
来锁定单元测试并让它们一个一个地执行:
[TestMethod]
public void ConstructionTest()
{
UnitTestSemaphoreLocker.Lock(() =>
{
//test body
});
}
对于一个程序集中的测试来说它工作得很好,但似乎其中两个创建了我自己的公共静态实例 UnitTestSemaphoreLocker
class.
有什么方法可以同步两个程序集的单元测试吗?同时其中一部分必须使用async/await
.
根据观察到的行为,Visual Studio测试运行ner (VSTest) 并行执行多个测试程序集。它启动多个进程(每个 CPU 核心最多一个)。每个这样的进程都包含它自己的 CLR 副本,每个副本加载一些 AppDomain,当然还有一个单独的测试程序集实例。
所有这些都意味着静态成员不共享,并且由于 SemaphoreSlim
依赖于 CLR 同步原语,所以同步不能跨 CLR 的多个实例工作。
我能想到两种可能的解决方案:
解决方案 1:跨进程同步
替换SemaphoreSlim with Semaphore. The latter can be initialized as a machine-wide named semaphore, allowing multiple processes to synchronize over same semaphore instance identified by a string name. See an example here. See also Semaphore and SemaphoreSlim以获取更多信息。
如果只有少数测试需要同步,这可能是一个很好的解决方案。但是,如果必须同步大部分或所有测试,运行 并行测试过程就没有意义——请参阅解决方案 #2。
解决方案 2:禁用并行测试进程
您可以通过 .runsettings
文件中的 <MaxCpuCount>
元素控制并行进程的数量。将其值设置为 1 应禁用并行进程:
<RunSettings>
<RunConfiguration>
<MaxCpuCount>1</MaxCpuCount>
</RunConfiguration>
</RunSettings>
有关详细信息,请参阅 Configure unit tests by using a .runsettings file。
这并不是说您不能并行化您的测试。 MSTest 有一个名为 "in-assembly parallel test execution" (IAP) 的功能,可以通过包含以下 assembly-level 属性(通常在 AssemblyInfo.cs 中)来启用该功能:
[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]
与生成进程的 VSTest 运行ner 相比,IAP 生成多个线程,所有线程共享同一个 AppDomain。在这种情况下,静态成员只有一个副本,CLR-based 与 SemaphoreSlim
同步也可以。
此 post 中有关 IAP 的更多信息:MSTest V2: in-assembly parallel test execution
我有 Common
和 class UnitTestSemaphoreLocker
:
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();
}
}
}
我有两个单元测试程序集,比方说 TestAssemblyA
和 TestAssemblyB
来自两个程序集的单元测试使用一种资源,每次只支持一次调用。
所以我希望你使用我的 UnitTestSemaphoreLocker
来锁定单元测试并让它们一个一个地执行:
[TestMethod]
public void ConstructionTest()
{
UnitTestSemaphoreLocker.Lock(() =>
{
//test body
});
}
对于一个程序集中的测试来说它工作得很好,但似乎其中两个创建了我自己的公共静态实例 UnitTestSemaphoreLocker
class.
有什么方法可以同步两个程序集的单元测试吗?同时其中一部分必须使用async/await
.
根据观察到的行为,Visual Studio测试运行ner (VSTest) 并行执行多个测试程序集。它启动多个进程(每个 CPU 核心最多一个)。每个这样的进程都包含它自己的 CLR 副本,每个副本加载一些 AppDomain,当然还有一个单独的测试程序集实例。
所有这些都意味着静态成员不共享,并且由于 SemaphoreSlim
依赖于 CLR 同步原语,所以同步不能跨 CLR 的多个实例工作。
我能想到两种可能的解决方案:
解决方案 1:跨进程同步
替换SemaphoreSlim with Semaphore. The latter can be initialized as a machine-wide named semaphore, allowing multiple processes to synchronize over same semaphore instance identified by a string name. See an example here. See also Semaphore and SemaphoreSlim以获取更多信息。
如果只有少数测试需要同步,这可能是一个很好的解决方案。但是,如果必须同步大部分或所有测试,运行 并行测试过程就没有意义——请参阅解决方案 #2。
解决方案 2:禁用并行测试进程
您可以通过 .runsettings
文件中的 <MaxCpuCount>
元素控制并行进程的数量。将其值设置为 1 应禁用并行进程:
<RunSettings>
<RunConfiguration>
<MaxCpuCount>1</MaxCpuCount>
</RunConfiguration>
</RunSettings>
有关详细信息,请参阅 Configure unit tests by using a .runsettings file。
这并不是说您不能并行化您的测试。 MSTest 有一个名为 "in-assembly parallel test execution" (IAP) 的功能,可以通过包含以下 assembly-level 属性(通常在 AssemblyInfo.cs 中)来启用该功能:
[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]
与生成进程的 VSTest 运行ner 相比,IAP 生成多个线程,所有线程共享同一个 AppDomain。在这种情况下,静态成员只有一个副本,CLR-based 与 SemaphoreSlim
同步也可以。
此 post 中有关 IAP 的更多信息:MSTest V2: in-assembly parallel test execution