Подтвердить что ты не робот

Единичное тестирование без утверждений

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

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

Просто интересно, что люди видят на этом?

4b9b3361

Ответ 1

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

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

// Assert
Assert.Null(ex);

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

Ответ 9

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

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

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

Ответ 13

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

Class Controller {
  private Validator validator;

  public void control(){
    validator.validate;
  }

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

Теперь, когда мы тестируем Controller, мы не хотим тестировать Validator, потому что у него есть собственные тесты. поэтому у нас есть тест с JMock, чтобы убедиться, что мы вызываем подтверждение:

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

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

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

Ответ 14

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

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

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

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