Следует ли отображать, что происходит в модульном тесте во время его выполнения?

#unit-testing

Вопрос:

Когда я кодирую свои модульные тесты, я, как правило, обнаруживаю, что вставляю следующие строки:

 Console.WriteLine("Starting InteropApplication, with runInBackground set to true...");
try
{
    InteropApplication application = new InteropApplication(true);
    application.Start();
    Console.WriteLine("Application started correctly");
}
catch(Exception e)
{
    Assert.Fail(string.Format("InteropApplication failed to start: {0}", e.ToString()));
}

//test code continues ...
 

Все мои тесты в значительной степени совпадают. Они отображают информацию о том, почему они потерпели неудачу, или они отображают информацию о том, что они делают. У меня не было никаких формальных методов кодирования модульных тестов. Должны ли они отображать информацию о том, что они делают? Или тесты должны быть беззвучными и вообще не отображать никакой информации о том, что они делают, и отображать только сообщения об ошибках?

ПРИМЕЧАНИЕ: Язык-C#, но меня не волнует ответ на конкретный язык.

Ответ №1:

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

Это кажется совершенно субъективным, но мне это кажется совершенно избыточной информацией, которая просто добавляет шума.

Ответ №2:

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

Ответ №3:

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

Ответ №4:

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

  1. Я не знаком с NUnit, но PyUnit позволяет добавлять описание теста, и когда тесты выполняются с опцией подробного описания, описание печатается. Я бы заглянул в документацию NUnit, чтобы узнать, можете ли вы это сделать.
  2. Расширьте класс TestCase, от которого вы наследуете, чтобы добавить функцию, из которой вы вызываете, которая регистрирует, что пытается сделать тест. Таким образом, различные реализации могут обрабатывать сообщения по-разному.

Ответ №5:

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

Ответ №6:

Мне нравится буферизировать подробный журнал (около последних 20 строк или около того), но я не отображаю его, пока он не приведет к какой-либо ошибке. Когда происходит ошибка, приятно иметь какой-то контекст.

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

Ответ №7:

Это может быть слишком специфично для языка, но когда я пишу тесты NUnit, я обычно делаю это, только я использую Систему.Диагностика.Библиотека трассировки вместо консоли, таким образом, информация отображается только в том случае, если я решу посмотреть трассировку.

Ответ №8:

Вам это не нужно, если тесты выполняются беззвучно, это означает, что ошибки не было. Обычно у тестов нет причин выдавать какие-либо результаты, кроме как в случае неудачи теста. Если он запущен, то бегун-тестер указывает, что тест пройден, то есть он «зеленый». Запустив тест (вместе со многими тестами с выводом на консоль) через программу запуска тестов в среде IDE, вы будете отправлять в журнал консоли сообщения, которые никого не будут волновать.

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

Ответ №9:

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

Ответ №10:

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

Однако в «нормальном» случае, когда все удается, эти сообщения являются ненужным беспорядком, который отвлекает от того, что вы действительно пытаетесь сделать, т. Е. рассмотрим обзор того, какие тесты прошли успешно, а какие провалились.

Я бы предложил перенаправлять ваши отладочные сообщения в файл журнала. Вы можете либо сделать это, написав весь свой код сообщения журнала для вызова специальной функции «печать журнала», либо, если вы пишете консольную программу, вы должны иметь возможность перенаправить вывод в другой файл (я точно знаю, что вы можете сделать это как в Unix, так и в Windows). Таким образом, вы получаете обзор высокого уровня, но детали есть, если они вам нужны.

Ответ №11:

Я бы не стал помещать дополнительные операторы Try/Catch в модульные тесты. Во-первых, ожидаемое исключение в модульном тесте уже приведет к сбою теста. Это поведение NUnit по умолчанию. По сути, тестовый жгут уже содержит этот код для каждого вызова ваших тестовых функций. Кроме того, просто используя e.toString() для отображения того, что произошло, я считаю, что вы теряете много информации. По умолчанию я считаю, что NUnit будет отображать не только тип исключения, но и стек вызовов, который, как я полагаю, вы не видите в своем методе.

Во-вторых, бывают моменты, когда это необходимо. Например, вы можете использовать атрибут [ExpectedException], чтобы фактически указать, когда это произойдет. Просто убедитесь, что при тестировании утверждений, не связанных с исключениями (например, утверждение количества списков > 0 и т. Д.), Вы вводите хорошее описание в качестве аргумента для утверждения. Это полезно.

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

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

1. e.toString() отображает трассировку стека.

Ответ №12:

Вы смотрели на стиль xUnit фреймворков модульного тестирования?
См. Сайт Рона Джеффриса для получения довольно большого списка.

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

Ответ №13:

Ну, вы должны знать только, когда тест провалился и почему он провалился. Бесполезно знать, что происходит, если, например, у вас нет цикла, и вы хотите точно знать, в каком месте цикла умер тест.

Ответ №14:

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

Ответ №15:

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

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

Ответ №16:

Вы могли бы написать метод тестирования так. Это зависит от вашего кода-нос, какой стиль тестирования вы предпочитаете. Я предпочитаю не писать дополнительные уловы и консоли.ПисьмЕнные линии.

 public void TestApplicationStart()
{
  InteropApplication application = new InteropApplication(true);
  application.Start();
}
 

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

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