Есть ли способ проверить, что установленный метод EventWaitHandle был вызван в модульном тестировании?

#multithreading #unit-testing #mocking #moq

#многопоточность #модульное тестирование #издевательство #moq

Вопрос:

Я пытался использовать mocking framework (Moq), но это не работает, потому что Set — это не переопределяемый метод. Затем я по глупости попытался создать свой собственный EventWaitHandle, расширив класс. Не похоже, что есть какой-либо момент, который я могу подключить в любом коде, чтобы определить, был ли set на самом деле вызван.

Я хочу сделать что-то похожее на Timer.Dispose(WaitHandle notifyObject), где кто-то может передать дескриптор ожидания, и я вызову set для него, когда что-то завершится.

Я бы предпочел сделать это без необходимости создавать класс-оболочку. Это просто кажется таким большим количеством дополнительных усилий и работы с обеих сторон, моей и пользователя, который должен использовать мой класс для создания оболочки.

Ответ №1:

К сожалению, это невозможно. Тем не менее, вы делаете это правильно — устраняете аспекты многопоточности кода, позволяя тестам выполняться в одном потоке. Затем Tests проверяет, что вызваны правильные методы ( Set в данном случае).

Я хотел бы .NET-framework был разработан в большей степени с учетом тестов, позволяя нам имитировать этот тип метода, позволяя классу реализовывать простой интерфейс.

Я был в такой же ситуации с этим точным методом, а также с некоторыми другими, у которых отсутствует интерфейс. В итоге я либо А) написал оболочку, Б) не написал тесты.

Комментарии:

1. Я делаю B прямо сейчас, потому что мне кажется, что слишком сложно для одного метода заставить пользователей API использовать оболочку.

Ответ №2:

Это далеко не идеально, но альтернативный подход заключается в создании отдельных задач для проверки выполнения вызова ‘Set’, одна для выполнения реальной работы, а другая для блокировки в WaitHandle. Тогда тест становится случаем ожидания завершения обеих задач (очевидно, добавляя тайм-ауты, чтобы предотвратить ожидание навсегда!).

Очень грубый пример может быть следующим:

     [Test]
    public void Test_Blocking()
    {
        // Arrange
        var ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
        System.Threading.Tasks.Task<int> blocker = BlockOn(ewh, 0);

        // Act
        System.Threading.Tasks.Task worker = Work(ewh);
        var allTasks = new[] { worker, blocker };
        while (!allTasks.All(t => t.IsCompleted))
        {
            // spin
        }

        // Assert            
        Assert.That(blocker.Result, Is.EqualTo(1));
    }

    private static System.Threading.Tasks.Task<int> BlockOn(EventWaitHandle waitHandle, int counter)
    {
        return System.Threading.Tasks.Task.Factory.StartNew<int>(() =>
        {
            waitHandle.WaitOne();
            return counter   1;
        });
    }