Вопрос

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

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

Просто интересно, каковы взгляды людей на это?

Это было полезно?

Решение

Это был бы официальный способ сделать это:

// Act
Exception ex = Record.Exception(() => someCode());

// Assert
Assert.Null(ex);

Другие советы

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

Если утверждения нет, то это не тест.

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

Они известны как испытания на задымление и являются распространенными.Это элементарная проверка на вменяемость.Но это не должны быть единственные виды тестов, которые у вас есть.Вам все равно понадобится какая-то проверка в другом тесте.

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

Я видел довольно много тестов, написанных таким образом, которые в итоге вообще ничего не тестировали, т.Е.код не сработал, но и не взорвался.

Если у вас есть какое-то явное требование о том, что тестируемый код не генерирует исключение, и вы хотите явно указать этот факт (тесты как документы требований), тогда я бы сделал что-то вроде этого:

try
{
  unitUnderTest.DoWork()
}
catch
{
  Assert.Fail("code should never throw exceptions but failed with ...")
}

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

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

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

Я думаю, если бы я видел это снова и снова в модульные тесты Мне было бы любопытно узнать, насколько полезными на самом деле были тесты.

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

Это может быть хорошим прагматичным решением, особенно если альтернативой является вообще отсутствие теста.

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

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

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

Название теста должно документировать это.

void TestLogDoesNotThrowException(void) {
    log("blah blah");
}

Как тест проверяет, записан ли журнал без утверждения?

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

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

Мы делаем это постоянно.Мы издеваемся над нашими зависимостями, используя JMock, так что я предполагаю, что в некотором смысле фреймворк JMock выполняет утверждение за нас...но это происходит примерно так.У нас есть контроллер, который мы хотим протестировать:

Class Controller {
  private Validator validator;

  public void control(){
    validator.validate;
  }

  public setValidator(Validator validator){ this.validator = validator; }
}

Теперь, когда мы тестируем контроллер, мы не хотим тестировать Валидатор, потому что у него есть свои собственные тесты.итак, у нас есть тест с JMock, просто чтобы убедиться, что мы вызываем validate:

public void testControlShouldCallValidate(){
  mockValidator.expects(once()).method("validate");
  controller.control;
}

И это все, нет никакого "утверждения", которое можно было бы увидеть, но когда вы вызываете control и метод "validate" не вызывается, фреймворк JMock выдает вам исключение (что-то вроде "ожидаемый метод не вызван" или что-то в этом роде).

У нас они есть повсюду.Это немного назад, так как вы в основном настраиваете свое утверждение, а затем выполняете вызов тестируемого метода.

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

Эти методы определенно не являются модульными тестами (даже несмотря на то, что они помечены [Тест] атрибут) и всегда помечаются как игнорируемые и явно документируются при их возврате в систему управления версиями.

Я также иногда использую эти методы в качестве точек входа для отладчика Visual Studio.Я использую Resharper для перехода непосредственно к тестированию, а затем к коду, который я хочу отладить.Эти методы либо не доходят до системы управления версиями, либо приобретают свои собственные утверждения.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top