Мы знаем, что пишем JUnit тестов демонстрирует один конкретный путь через ваш код.
Один из моих партнеров прокомментировал:
Написание модульных тестов вручную - это Proof By Example .
Он пришел из истории Haskell, который имеет такие инструменты, как Quickcheck и способность рассуждать о поведении программы с типами .
Он подразумевал, что существует множество других комбинаций входных данных, которые не проверяются этим методом, для которых ваш код не тестируется.
У меня вопрос: пишут ли модульные тесты вручную Proof By Example?
unit-testing
junit
Hawkeye
источник
источник
Ответы:
Если вы случайным образом выбираете входные данные для тестирования, тогда, я полагаю, возможно, вы используете логическую ошибку Proof By Example.
Но хорошие юнит-тесты никогда не делают этого. Вместо этого они имеют дело с диапазонами и крайними случаями.
Например, если вы хотите написать модульные тесты для функции абсолютного значения, которая принимает целое число в качестве входных данных, вам не нужно проверять каждое возможное значение входных данных, чтобы доказать, что код работает. Чтобы получить исчерпывающий тест, вам потребуется всего пять значений: -1, 0, 1, а также значения max и min для входного целого числа.
Эти пять значений проверяют каждый возможный диапазон и границу функции. Вам не нужно проверять каждое возможное входное значение (т. Е. Каждое число, которое может представлять целочисленный тип), чтобы получить высокий уровень достоверности, что функция работает для всех входных значений.
источник
int foo(int x) { return 1234/(x - 100); }
. Также обратите внимание, что (в зависимости от того, что вы тестируете) вам может потребоваться убедиться, что неверный («вне диапазона») ввод верных результатов (например, что `` find_thing (thing) `" правильно возвращает какой-то статус «не найден» если вещь не была найдена).-Inf
,Inf
,NaN
,1e-100
,-1e-100
,-0
,2e200
... Я бы предпочел не делать те все вручную.Любое тестирование программного обеспечения похоже на «Proof By Example», а не только на модульное тестирование с использованием такого инструмента, как JUnit. И это не новая мудрость, есть цитата из Дейкстры 1960 года, которая говорит, по сути, то же самое:
(просто замените слова «показывает» на «доказательства»). Однако это также верно для инструментов, которые генерируют случайные тестовые данные. Количество возможных входных данных для функции реального мира обычно на порядки больше, чем количество тестовых случаев, которые можно произвести и проверить по ожидаемому результату в возрасте вселенной, независимо от метода генерации этих случаев, поэтому даже если кто-то использует инструмент генератора для получения большого количества тестовых данных, нет гарантии, что вы не пропустите один тестовый случай, который мог бы обнаружить определенную ошибку.
Случайные тесты могут иногда выявить ошибку, которая была пропущена вручную созданными тестовыми примерами. Но в целом более эффективно тщательно создавать тесты для функции, подлежащей тестированию, и следить за тем, чтобы получить полный код и охват ветвлений с как можно меньшим количеством тестовых случаев. Иногда целесообразно комбинировать вручную и случайно сгенерированные тесты. Более того, при использовании случайных тестов нужно позаботиться о том, чтобы результаты были воспроизводимыми.
Таким образом, созданные вручную тесты ничуть не хуже, чем случайно сгенерированные тесты, часто наоборот.
источник
Написание тестов вручную является «доказательством на примере». Но так же QuickCheck, и в ограниченной степени типа систем. Все, что не является прямой формальной проверкой, будет ограничено в том, что оно говорит вам о вашем коде. Вместо этого вы должны думать с точки зрения относительной заслуги подходов.
Генеративное тестирование, такое как QuickCheck, действительно хорошо подходит для широкого круга входных данных. Это также намного лучше для решения крайних случаев, чем ручные тесты: библиотеки генеративного тестирования будут иметь больше опыта, чем вы. С другой стороны, они говорят только об инвариантах, а не о конкретных выходных данных. Таким образом, чтобы убедиться, что ваша программа дает правильные результаты, вам все еще нужны ручные тесты, чтобы убедиться в этом
foo(bar) = baz
.источник