Как модульно протестировать метод, который запускается в бесконечном цикле для некоторого ввода?

#unit-testing #junit #tdd #nunit #infinite-loop

#модульное тестирование #junit #tdd #nunit #бесконечный цикл

Вопрос:

Этот вопрос только что пришел мне в голову, и я хочу задать его здесь.

Случай преднамеренный, я просто пишу цикл, который выполняется бесконечно. Как мне приступить к модульному тестированию?

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

  • Как он запускался в бесконечный цикл
  • Какой набор входных данных вызвал это
  • Вызов какого метода (из этого метода) вызвал это

У меня нет написанного для этого кода. Вопрос чисто для ознакомления относительно того, что делать, если такая ситуация возникнет в будущем. Пожалуйста, ответьте.

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

1. Является ли бесконечный цикл преднамеренным? Также, google «проблема с остановкой».

2. Могу ли я узнать причину от того, кто попросил закрыть этот вопрос, относительно того, почему его следует закрыть?

3. @dlev, да, это сделано намеренно. Это просто пришло мне в голову, когда я думал о ситуации, когда это может произойти

4. @Shankar: когда предполагается получить результат от этого метода?

5. @Shankar: можете ли вы привести какой-либо пример?

Ответ №1:

Как модульно протестировать метод, который запускается в бесконечном цикле для некоторого ввода?

Вы можете протестировать почти противоположное: «Как модульно протестировать метод, чтобы он не выполнялся дольше Xxxx миллисекунд для некоторого ввода». Если этот тест завершается неудачей, возможно, вы нашли кандидата с бесконечным циклом.

В NUnit 2.5 есть атрибут TimeoutAttribute, который приводит к сбою теста, если тест занимает больше времени, чем заданное количество миллисекунд.

Ответ №2:

Есть ли функция, которая выполняет циклы, делегирующая проверку цикла введенной зависимости:

 interface IShouldLoop
{
    bool ShouldLoop();
}

class ClassToTest
{
    private final IShouldLoop shouldLoop;

    public ClassToTest(IShouldLoop shouldLoop)
    {
        this.shouldLoop = shouldLoop;
    }

    public void MethodToTest()
    {
        while(shouldLoop.ShouldLoop())
        {
            // do whatever
        }
    }
}
  

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

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

1. Мне нравится этот подход. Я думаю, что имена LoopCondition и isTrue() имеют больше смысла.

2. Другой вариант — пометить метод как виртуальный и переопределить его для тестирования

Ответ №3:

Я надеюсь, вы имеете в виду какой-то цикл перекачки сообщений / обработки событий. (Большинство бесконечных циклов плохие).

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

Вероятность того, что конструкция цикла не сработает, минимальна.. Поэтому я бы протестировал это с помощью приемочного теста или вручную.

Это несколько похоже на тестирование основной функции исполняемого файла. Хитрость здесь также заключается в том, чтобы гарантировать, что Main делегирует тестируемый класс.

Ответ №4:

Цель unitesting — протестировать каждый самый простой модуль в вашей программе.

Обычно самый простой модуль — это функция, которая выполняет одно задание, поэтому, чтобы объединить ваш бесконечный цикл, вам нужно будет извлечь каждое отдельное задание, которое этот цикл мог бы выполнить, в отдельную функцию, которая может вызываться отдельно, после этого вы сможете вызывать эти функции, учитывая их все возможные параметры, чтобы протестировать различные конфигурации, которые ваша функция должна уметь обрабатывать. Не обязательно объединять бесконечный цикл как функцию, но меньшие миссии внутри него.