Как к TDD асинхронные события?

Фундаментальный вопрос состоит в том, как я создаю модульный тест, который должен назвать метод, ожидать события, чтобы произойти на протестированном классе и затем назвать другой метод (тот, который мы на самом деле хотим протестировать)?

Вот сценарий, если у Вас есть время для чтения далее:

Я разрабатываю приложение, которое должно управлять частью аппаратных средств. Для предотвращения зависимости от аппаратной доступности, когда я создаю свой объект, я указываю, что мы работаем в тестовом режиме. Когда это происходит, класс, который тестируется, создает соответствующую иерархию драйвера (в этом случае тонкий ложный слой драйверов оборудования).

Предположите, что рассматриваемым классом является Лифт, и я хочу протестировать метод, который дает мне число пола, которое лифт. Вот то, как мой фиктивный тест похож прямо сейчас:

[TestMethod]
public void TestGetCurrentFloor()
{
    var elevator = new Elevator(Elevator.Environment.Offline);
    elevator.ElevatorArrivedOnFloor += TestElevatorArrived;

    elevator.GoToFloor(5);

    //Here's where I'm getting lost... I could block
    //until TestElevatorArrived gives me a signal, but
    //I'm not sure it's the best way

    int floor = elevator.GetCurrentFloor();

    Assert.AreEqual(floor, 5);
}

Править:

Спасибо за все ответы. Это - то, как я закончил тем, что реализовал его:

    [TestMethod]
    public void TestGetCurrentFloor()
    {
        var elevator = new Elevator(Elevator.Environment.Offline);
        elevator.ElevatorArrivedOnFloor += (s, e) => { Monitor.Pulse(this); };

        lock (this)
        {
            elevator.GoToFloor(5);

            if (!Monitor.Wait(this, Timeout))
                Assert.Fail("Elevator did not reach destination in time");

            int floor = elevator.GetCurrentFloor();

            Assert.AreEqual(floor, 5);
        }
    }
12
задан Padu Merloti 11 March 2010 в 17:42
поделиться

3 ответа

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

Для этого в тесте можно использовать Monitor.Wait с таймаутом, а когда событие наступит, сигнализировать об этом с помощью Monitor.Pulse.


[TestMethod]
public void TestGetCurrentFloor()
{
    var elevator = new Elevator(Elevator.Environment.Offline);
    elevator.ElevatorArrivedOnFloor += TestElevatorArrived;

    lock (this)
    {
        elevator.GoToFloor(5); // NOTE: this must hand off to a second thread, and the ElevatorArrivedOnFloor must be raised by this other thread otherwise the Monitor will be pulse before we've started waiting for it

        if (!Monitor.Wait(this, TIMEOUT)) Assert.Fail("Event did not arrive in time.");
    }

    int floor = elevator.GetCurrentFloor();

    Assert.AreEqual(floor, 5);
}

private void TestElevatorArrived(int floor)
{
    lock (this)
    {
        Monitor.Pulse(this);
    }
}

(Вызов Assert.Fail() здесь должен быть заменен на любой механизм, который использует ваш инструмент модульного тестирования для явного отказа теста - или вы можете бросить исключение)

.
5
ответ дан 2 December 2019 в 22:37
поделиться

Возможно, это просто плохой пример, но ваш лифт больше похож на конечный автомат, чем на то, что просто обрабатывает асинхронно.

Итак, ваш первый набор тестов может проверить, что GoToFloor () установит состояние в движение и что направление его движения правильное.

Затем следующий набор тестов будет на TestElevatorArhibited () и будет проверять, что если ваше состояние движется к определенному этажу, то фактическое движение (то есть функция, вызываемая после асинхронного ожидания, или обработчик для оборудование, запускающее событие 'перемещено') установит состояние на ожидаемый этаж.

В противном случае то, что вы тестируете, скорее всего, будет тем, что ваше издевательство над оборудованием правильно имитирует время и движение, что не кажется правильным.

2
ответ дан 2 December 2019 в 22:37
поделиться

Это мой аналогичный подход.

    [TestMethod]
    public void TestGetCurrentFloor()
    {
        var completedSync = new ManualResetEvent(false);
        var elevator = new Elevator(Elevator.Environment.Offline);

        elevator.ElevatorArrivedOnFloor += delegate(object sender, EventArgs e)
        {
            completedSync.Set();
        };

        elevator.GoToFloor(5);

        completedSync.WaitOne(SOME_TIMEOUT_VALUE);

        int floor = elevator.GetCurrentFloor();

        Assert.AreEqual(floor, 5);
    } 

Вы также можете проверить возвращаемое значение вызова WaitOne (), чтобы убедиться, что ваш обработчик событий был вызван.

2
ответ дан 2 December 2019 в 22:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: