Если у вас должно быть только одно утверждение на тест; Как проверить несколько входов?

15

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

Поэтому мой вопрос заключается в том, как лучше всего протестировать функцию с несколькими входами. Например, у меня есть функция, которая анализирует строку у пользователя и возвращает количество минут. Строка может иметь вид "5w6h2d1m", в котором w, h, d, mуказано количество недель, часов, дней и минут.

Если бы я хотел следовать «1 утверждению на правило теста», мне пришлось бы сделать несколько тестов для каждого варианта ввода? Это кажется глупым, поэтому вместо этого у меня есть что-то вроде:

self.assertEqual(parse_date('5m'), 5)
self.assertEqual(parse_date('5h'), 300)
self.assertEqual(parse_date('5d') ,7200)
self.assertEqual(parse_date('1d4h20m'), 1700)

В одном тестовом случае. Есть ли способ лучше?

SPEG
источник
Лучший способ сделать это - использовать параметры (некоторые фреймворки поддерживают эту функцию, все фреймворки должны). Таким образом, вы тестируете одиночное поведение, но принимаете во внимание множество тестовых случаев и по-прежнему можете видеть, какие значения параметров вызвали ошибку в случае ошибки
Kemoda

Ответы:

23

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

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

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

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

жилль
источник
17

Это очень сильно зависит от вашей тестовой библиотеки. В библиотеке C # NUnit вы можете делать что-то вроде:

[TestCase('5m', 5)]
[TestCase('5h', 300)]
[TestCase('5d', 7200)]
[TestCase('1d4h20m', 1700)]
public void ParseDateTest(inputString, expectedMinutes)
{
    Assert.That(parse_date(inputString), Is.EqualTo(expectedMinutes));
}
Scroog1
источник
В Java с testng у вас есть методы
@DataProvider
это лучшее решение ИМХО. почти на каждом языке вы можете параметризовать свои тесты. для Java: @Parameterized , JunitParams , Zohhak
piotrek
3

Да, сделайте несколько тестов для каждого варианта ввода.

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

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

Но история показала, что экономить немного времени на написание кода за счет чтения / использования кода никогда не стоит. Отсюда и руководство.

Telastyn
источник
1

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

При тестировании с JUnit мы можем обойти это, используя версию методов assert * с начальным аргументом String, чтобы отличить одно утверждение от другого в том же методе теста.

self.assertEqual("just minutes", parse_date('5m'), 5)
self.assertEqual("just hours", parse_date('5h'), 300)
self.assertEqual("just days", ('5d') ,7200)
self.assertEqual("days, hours, minutes", parse_date('1d4h20m'), 1700)
Майк Партридж
источник