Синхронизировать несколько сборочных тестов - PullRequest
0 голосов
/ 30 июня 2019

У меня есть сборка Common с классом 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 класс.

Можно ли синхронизировать модульный тест из двух сборок?Между тем часть из них должна использовать async/await.

1 Ответ

2 голосов
/ 30 июня 2019

В соответствии с наблюдаемым поведением, средство выполнения тестов Visual Studio (VSTest) выполняет несколько сборок теста параллельно. Он запускает несколько процессов (не более одного на ядро ​​процессора). Каждый такой процесс содержит свою собственную копию CLR, каждый из которых загружает некоторый AppDomain и, конечно, отдельный экземпляр тестовой сборки.

Все это означает, что статические члены не являются общими, а также что синхронизация не работает для нескольких экземпляров CLR из-за SemaphoreSlim, который опирается на примитивы синхронизации CLR.

Я могу придумать два возможных решения:

Решение 1: синхронизация между процессами

Заменить СемафорSlim на Семафор . Последний может быть инициализирован как семафор с именем компьютера, что позволяет нескольким процессам синхронизироваться по одному и тому же экземпляру семафора, идентифицированному по имени строки. См. пример здесь . См. Также Semaphore и SemaphoreSlim для получения дополнительной информации.

Если только некоторые из ваших тестов требуют синхронизации, это может быть хорошим решением. Однако, если большинство или все тесты должны быть синхронизированы, нет смысла запускать параллельные тестовые процессы - см. Решение №2.

Решение 2: отключить параллельные процессы тестирования

Вы можете контролировать количество параллельных процессов через элемент <MaxCpuCount> в файле .runsettings. Установка его значения в 1 должна отключить параллельные процессы:

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

Подробнее см. Настройка модульных тестов с использованием файла .runsettings .

Это не значит, что вы не можете распараллелить свои тесты. MSTest имеет функцию под названием «Выполнение параллельного теста в сборке» (IAP), которую можно включить, включив следующий атрибут уровня сборки (обычно в AssemblyInfo.cs ):

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

В отличие от бегуна VSTest, который порождает процессы, IAP порождает несколько потоков, все из которых используют один и тот же домен приложения. В этом случае есть только одна копия статических членов, и синхронизация на основе CLR с SemaphoreSlim также работает.

Подробнее о IAP в этом сообщении: MSTest V2: выполнение параллельного теста в сборке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...