Как вы решаете проблему бесконечного регресса в TDD? - PullRequest
1 голос
/ 22 января 2010

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

Как решается эта проблема (на практике и в теории)?

Ответы [ 8 ]

5 голосов
/ 22 января 2010

Тест проверяет код, а код проверяет тест.

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

2 голосов
/ 22 января 2010

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

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

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

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

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

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

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

Но моя главная задача состояла в том, чтобы оспорить то, что, как я понимаю, является предпосылкой вопроса: как TDD может обеспечить 100% безошибочный код, если в самих тестах могут быть ошибки. Мой ответ на это предположение, что он не может. Это делает что-то еще (дизайн дисков). Я надеюсь, что это проясняет ситуацию.

1 голос
/ 22 января 2010

У меня недавно была дискуссия с кем-то об этом на работе. Человек, поднимающий проблему, был справедлив, но в конечном итоге юнит-тестирование - это практичная, проверенная методика. TDD добавляет еще один аспект «сначала тест», который еще больше снижает вероятность того, что тест будет некорректным, поскольку он должен завершиться неудачей, прежде чем будет написан какой-либо производственный код. Хотя тесты могут быть ошибочными, на мой взгляд, эта проблема скорее философская дискуссия, чем практический барьер.

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

Пример : До NUnit 2.5 у нас был повторно используемый класс тестирования на основе данных. Он использовался и использовался многими другими тестами, плюс он был довольно сложным. Конечно, достаточно сложный, чтобы иметь ошибки. Таким образом, мы проверили тестовый класс. ... а затем, когда вышел NUnit 2.5, мы поменяли все тесты, чтобы использовать его, и выбросили нашу собственную реализацию.

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

1 голос
/ 22 января 2010

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

0 голосов
/ 22 января 2010

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

0 голосов
/ 22 января 2010

Напишите ваши тесты как можно проще.

Тогда у вас будет эффективный цикл, когда ваш код станет максимально простым для тестирования тестов.

Или так преобладает теория.

0 голосов
/ 22 января 2010

Модульные тесты не предназначены для 100% защиты от ошибок. Это просто техника для улучшения качества кода. Никогда не практиковав TDD, можно подумать, что общее качество кода не улучшится, если добавить тест, который должен пройти, DOH!

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

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

Модульные тесты неоценимы как инструмент регрессии. Макрорегрессия (как в днях, неделях, годах после написания кода) и микрорегрессия (при написании кода). Кстати, я полностью придумываю эти термины. Если они на самом деле являются терминами, используемыми Мартином Фаулером или дядей Бобом, это означает, что я такой же блестящий, как и они :) Шучу.

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

При использовании TDD все варианты использования (тесты) для реализуемой вами функциональности остаются. Это означает, что вы в значительной степени уверены, что все, что вы добавите позже, не нарушит более простой код.

0 голосов
/ 22 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...