Как мне проверить мой тестовый код?

22

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

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

Мне кажется, что лучший способ сделать это - убедиться в том, что тест завершился неудачно для кода с ошибками. * Если я потрачу 2 минуты попеременно на добавление ошибок в код и убедитесь, что он не работает, у меня должна быть приемлемая степень уверенности в том, что тесты «работа». Это подводит меня ко второму вопросу: как можно исправить ошибки, чтобы убедиться, что они обнаружены тестовыми примерами? Должен ли я просто случайно закомментировать операторы, убедиться, что if-elseзапускается неправильная ветвь an , отрицая ее условие, и изменить порядок выполнения кода с побочными эффектами и т. Д., Пока я не буду удовлетворен, мои тесты поймают большинствообщие ошибки? Как профессиональные разработчики подтверждают, что их тесты действительно выполняют то, что должны делать? Они просто предполагают, что тесты работают, или они тоже не торопятся? Если да, то как они тестируют тесты?

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

* Я мог бы проверить, проходит ли тест при тестировании «безошибочного» кода, но использование кода в качестве спецификации для теста выглядит довольно задом наперед ...

Гордон Густафсон
источник
Похоже, вы не уверены в своих модульных тестах - скорее всего потому, что вам не хватает большого опыта в написании тестов? В этом случае было бы неразумно писать больше тестов и ожидать другого результата. Просто продолжайте делать то, что вы делаете, будьте как можно тщательнее (проверяйте как неудачи, так и успехи), и вскоре ваши юнит-тесты начнут окупаться - и ваша уверенность в них возрастет.
MattDavey
Возможный дубликат Как проверить тесты?
комар
Прежде чем использовать больше инструментов, лучше используйте ваши настоящие инструменты . Пишите меньше тестов, но более эффективные и лучше написанные тесты. Вы не можете доверять тому, чего не понимаете.
Стив Шамайяр

Ответы:

16

Стандартный поток для TDD:

  1. Напишите провальный тест. (Красный)
  2. Сделайте наименьшее изменение кода, чтобы оно прошло (зеленый)
  3. Refactor (Сохраняя это зеленым)

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

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

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

Bringer128
источник
4
Двойная бухгалтерия: модульные тесты проверяют производственный код и наоборот. Это два разных способа сформулировать одну и ту же проблему. Как и в двойной бухгалтерии, где вы записываете свои транзакции двумя разными способами, и оба должны получать одинаковые итоги.
EricSchaefer
Вопрос заключается в проблеме, когда шаг 2 делает тест зеленым, хотя код все еще глючит. Простой пример: у вас есть функция, которая должна возвращать указатель на непустой объект списка. Ваш тест проверяет, является ли указатель nullи не работает ли он на шаге 1. Вы вносите наименьшее изменение в код, которое пропускает его, возвращая пустой список. Тест теперь "зеленый", потому что у вас есть две ошибки.
Кристиан Хакл
@ChristianHackl на этом этапе разработки это идеальная реализация! Вы должны добавить один (или несколько) тестов, которые сначала не пройдут, чтобы дополнительно указать ожидаемое поведение. Впоследствии вы реализуете его, делая эти тесты зелеными.
Энди
@ Энди: Не могли бы вы уточнить, как это идеальная реализация, когда у меня есть ошибка как в коде, так и в тесте, и одна мешает мне заметить другую? (Ошибка в коде заключается в том, что возвращается пустой список, а ошибка в тесте заключается в том, что я проверяю, nullа не проверяю пустую.)
Кристиан Хакл,
@ChristianHackl вы правы по пустому чеку. Это, действительно, должно быть сделано и в тесте. Когда вы переводите свои требования в тесты, шаг за шагом остается мало места для ошибок. За исключением тех случаев, когда вы не придерживаетесь спецификации (например, пропускаете не пустой чек).
Энди
9

Одним из подходов является Mutation Testing , использующий такой инструмент, как Jester :

Jester вносит некоторые изменения в ваш код, запускает ваши тесты, и если тесты проходят успешно, Jester отображает сообщение о том, что он изменил

Парсифаль
источник
4

Тесты для тестов? Не иди по этой дороге. Тогда вам, вероятно, понадобятся тесты для тестов на тесты, а затем тесты для тестов на тесты для тестов ... где вы остановитесь?

Обычный процесс тестирования выглядит следующим образом, и, как разработчик, вы будете тратить большую часть своего времени на пункты 1-3:

  1. Код
  2. Модульные тесты
  3. Интеграционные тесты
  4. Система / другое автоматизированное
  5. QA / человек тестеры

Если я потрачу 2 минуты попеременно на добавление ошибок в код (...)

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

Если я просто закомментирую операторы случайным образом, убедитесь, что неверная ветвь if-else запускается путем отмены ее условия (...)

Это действительно жизнеспособный подход для проверки того, действительно ли вы тестируете то, что, по вашему мнению, делаете. Я не думаю, что это всегда так хорошо, поскольку страдает от той же проблемы, что и «тест для теста для теста ...»: когда вы прекращаете изменять код, зная, что код, который вы тестируете на 100%, работает?

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

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

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

mouviciel
источник
0

Вы тестируете свой модульный тест один раз, когда пишете его, в отладчике. Тогда оставь это в покое и забудь об этом. Здесь нет проблем.

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

Мартин Маат
источник
-2

Существует мутационное тестирование, которое оценивает и измеряет пригодность и качество теста.

Мы можем использовать это, чтобы оценить сам «тест».

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

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

Chickenchaser
источник