#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;
});
}