Результаты модульного тестирования, полученные обработанным потоком - PullRequest
0 голосов
/ 22 июня 2010

У меня есть модульный тест, в котором я макетирую (с помощью moq) объект и позволяю ему проверить, правильно ли он выполнил метод. Этот метод выполняется в потоке, который я создаю в моем SUT (тестируемая система). Когда я хочу выполнить VerifyAll () для Mock, может случиться так, что Thread все еще работает и что он еще не завершен, пока не выполняется метод - не пройден тест.

Есть ли способ решить это в правильном вопросе? например пусть VerifyAll подождет или как? Потому что сейчас тест ненадежен.

Это тест:

    [Test]
    public void TryToExecute_SubjectNotYetBeingProcessed_ProcessesSubject()
    {
        var subject = new Subject();
        var rule = new Mock<IBusinessRule>();
        rule.Setup(x => x.RunChildren(subject)); //RunChildren will be called in a seperate Thread

        InBuffer.TryToExecute(subject, rule.Object);

        rule.VerifyAll(); //It could be possible that the Thread is still running and that RunChildren() isn't invoked yet, thus failing the test.
    }

    public void TryToExecute(Subject subject, IBusinessRule rule){
        var thread = new Thread(x =>
                {
                    SetCurrentAsProcessing(subject);
                    rule.RunChildren(subject) // This is where it executes
                    RemoveFromProcess(subject);
                });

        thread.Start(); // Start the Thread
    }

Ответы [ 2 ]

1 голос
/ 22 июня 2010

Если в вашем классе реализован какой-то механизм для ожидания завершения асинхронной операции, то вам следует использовать его в своем тесте.

Если нет, вы можете попробовать этот "взлом" (не проверено - я не знаюваш фальшивый фреймворк, и я не уверен, как заставить его запускать methodCalled.Set ()):

[Test]
public void TryToExecute_SubjectNotYetBeingProcessed_ProcessesSubject()
{
    ManualResetEvent methodCalled = new ManualResetEvent(false);

    var subject = new Subject();
    var rule = new Mock<IBusinessRule>();
    rule.Setup(x => x.RunChildren(subject)).Do(X=>methodCalled.Set()); //RunChildren will be called in a seperate Thread

    InBuffer.TryToExecute(subject, rule.Object);

    Assert.IsTrue(methodCalled.WaitOne(1000), "RunChildren was not called within 1000ms");
}

Обратите внимание, что такой подход не является ни приятным, ни безопасным, поэтому избегайте, если у вас есть альтернатива.

0 голосов
/ 23 июня 2010

Использовать монитор в тесте:

Monitor.Enter(lock)
Monitor.Wait(lock, timeout) // Will pause here until pulsed or timed out
Monitor.Exit(lock)

В вашем макете используйте обратный вызов для уведомления монитора (Примечание: моя версия MoQ использует Callback вместо Do):

rule.Setup(x => x.RunChildren(subject)).Do( X => {
    ...
    Monitor.Enter(lock);
    Monitor.Pulse(lock);
    Monitor.Exit(lock);
}

Здесь есть несколько примеров использования мониторов (часть инфраструктуры тестирования автоматизации):

http://code.google.com/p/wipflash/source/browse/WiPFlash/Components/AutomationElementWrapper.cs

...