Я просматривал документы phpunit и наткнулся на следующую цитату:
Вы всегда можете написать больше тестов. Однако вы быстро обнаружите, что только часть тестов, которые вы можете себе представить, действительно полезны. Вам нужно написать тесты, которые не будут работать, даже если вы считаете, что они должны работать, или тесты, которые пройдут успешно, даже если вы считаете, что они должны провалиться. Другой способ думать об этом с точки зрения затрат / выгод. Вы хотите написать тесты, которые окупят вас информацией. - Эрих Гамма
Это заставило меня задуматься. Как вы определяете, что делает юнит-тест более полезным, чем другой, кроме того, что указано в этой цитате о соотношении цена / качество. Как вы решаете, для какой части вашего кода вы создаете модульные тесты? Я спрашиваю это, потому что другая из этих цитат также сказала:
Так что, если речь идет не о тестировании, о чем оно? Речь идет о том, чтобы выяснить, что вы пытаетесь сделать, прежде чем пытаться это сделать. Вы пишете спецификацию, которая фиксирует небольшой аспект поведения в краткой, однозначной и выполнимой форме. Это так просто. Значит ли это, что вы пишете тесты? Нет. Это означает, что вы пишете спецификации того, что должен делать ваш код. Это означает, что вы заранее определяете поведение своего кода. Но не намного раньше времени. На самом деле, лучше всего, прежде чем писать код, потому что у вас под рукой столько информации, сколько у вас будет до этого момента. Как и хорошо сделанный TDD, вы работаете с небольшими приращениями ... определяя один небольшой аспект поведения за раз, затем реализуя его. Когда вы понимаете, что все дело в определении поведения, а не в написании тестов, ваша точка зрения меняется. Внезапно идея иметь тестовый класс для каждого из ваших производственных классов смехотворно ограничивает. И мысль о тестировании каждого из ваших методов с помощью собственного метода тестирования (в соотношении 1: 1) будет смешной. - Дэйв Астелс
Важный раздел этого
* И мысль о тестировании каждого из ваших методов с помощью собственного метода тестирования (в соотношении 1: 1) будет смешной. *
Итак, если создание теста для каждого метода «смешно», как и когда вы выбрали то, для чего пишете тесты?
источник
Ответы:
Сколько тестов на метод?
Ну, теоретический и крайне непрактичный максимум - сложность N-Path (предположим, что все тесты охватывают код различными способами;)). Минимум ОДИН !. Для открытого метода, то есть он не тестирует детали реализации, только внешние поведения класса (возвращают значения и вызывают другие объекты).
Вы цитируете:
а затем спросите:
Но я думаю, что вы неправильно поняли автора здесь:
Идея «
one test method
пер»one method in the class to test
- это то, что автор называет «смехотворным».(По крайней мере, для меня) Это не о «меньше», а о «больше»
Итак, позвольте мне перефразировать, как я понял его:
И мысль о тестировании каждого из ваших методов ТОЛЬКО ОДНЫМ МЕТОДОМ (его собственный метод тестирования в соотношении 1: 1) будет смешной.
Чтобы процитировать вашу цитату снова:
Когда вы практикуете TDD, вы не думаете :
У меня есть метод,
calculateX($a, $b);
и ему нужен тест,testCalculcateX
который проверяет ВСЕ о методе.TDD говорит вам о том, что ваш код ДОЛЖЕН ДЕЛАТЬ :
Мне нужно вычислить большее из двух значений ( первый тестовый случай! ), Но если $ a меньше нуля, то это должно привести к ошибке ( второй тестовый случай! ), А если $ b меньше нуля, это должно произойти .... ( третий тестовый кейс! ) и тд.
Вы хотите проверить поведение, а не только отдельные методы без контекста.
Таким образом, вы получаете набор тестов, который является документацией для вашего кода и ДЕЙСТВИТЕЛЬНО объясняет, что он должен делать, возможно, даже почему :)
Как вы решаете, для какой части вашего кода вы создаете модульные тесты?
Что ж, все, что попадает в хранилище или где-то рядом с производством, нуждается в проверке. Я не думаю, что автор ваших цитат не согласился бы с этим, как я пытался заявить в вышесказанном.
Если у вас нет теста для него, становится намного сложнее (дороже) изменить код, особенно если это не вы вносите изменения.
TDD - это способ гарантировать, что у вас есть тесты на ВСЕ, но пока вы ПИШИТЕ тесты, все в порядке. Обычно написание их в один и тот же день помогает, потому что вы не собираетесь делать это позже, не так ли? :)
Ответ на комментарии:
Есть три вещи, которые эти методы могут вызывать:
Публичные методы других классов
Мы можем смоделировать другие классы, чтобы мы определили состояние там. Мы контролируем контекст, так что это не проблема.
* Защищенные или частные методы на том же *
Все, что не является частью общедоступного API класса, обычно не тестируется напрямую.
Вы хотите проверить поведение, а не реализацию, и если класс выполняет все, он работает в одном большом публичном методе или во многих меньших защищенных методах, которые вызываются, является реализацией . Вы хотите иметь возможность ИЗМЕНИТЬ эти защищенные методы БЕЗ касания ваших тестов. Потому что ваши тесты сломаются, если ваш код изменит поведение! Вот для чего нужны ваши тесты, чтобы сказать вам, когда вы что-то сломаете :)
Открытые методы в одном классе
Это случается не очень часто, не так ли? И если это так, как в следующем примере, есть несколько способов справиться с этим:
То, что сеттеры существуют и не являются частью сигнатуры метода execute, является другой темой;)
Что мы можем проверить здесь, так это то, что, если execute устанавливает значение, когда мы устанавливаем неправильные значения Это
setBla
выдает исключение, когда вы передаете строку, может быть протестировано отдельно, но если мы хотим проверить, что эти два допустимых значения (12 и 14) не работают ВМЕСТЕ (по какой-либо причине), чем это один тестовый пример.Если вам нужен «хороший» набор тестов, вы можете, в php, возможно (!) Добавить
@covers Stuff::execute
аннотацию, чтобы убедиться, что вы генерируете только покрытие кода для этого метода, а другие просто настраиваемые вещи нужно тестировать отдельно (опять же, если ты хочешь это).Итак, суть в том, что сначала вам нужно создать какой-то окружающий мир, но вы должны быть в состоянии написать значимые тестовые примеры, которые обычно охватывают только одну или, возможно, две реальные функции (сеттеры здесь не учитываются). Остальные могут быть издевались над эфиром или сначала проверяться, а затем полагаться (см.
@depends
)* Примечание: вопрос был перенесен из SO и изначально касался PHP / PHPUnit, поэтому пример кода и ссылки взяты из мира php, я думаю, что это также применимо к другим языкам, так как phpunit не так сильно отличается от других xUnit рамки тестирования.
источник
Тестирование и модульное тестирование - это не одно и то же. Модульное тестирование является очень важной и интересной частью общего тестирования. Я бы сказал, что фокус модульного тестирования заставляет нас задуматься об этом виде тестирования способами, которые несколько противоречат приведенным выше цитатам.
Во-первых, если мы следуем TDD или даже DTH (т.е. разрабатываем и тестируем в тесной гармонии), мы используем тесты, которые мы пишем, чтобы сосредоточиться на правильном дизайне. Думая об угловых случаях и написав соответствующие тесты, мы в первую очередь избегаем появления ошибок, поэтому на самом деле мы пишем тест, который ожидаем пройти (хорошо, в самом начале TDD они терпят неудачу, но это всего лишь упорядоченный артефакт, когда код готов, мы ожидаем, что они пройдут, и большинство делают, потому что вы думали о коде.
Во-вторых, модульные тесты действительно вступают в свои права, когда мы проводим рефакторинг. Мы меняем нашу реализацию, но ожидаем, что ответы останутся прежними - модульное тестирование - это наша защита от нарушения нашего интерфейса интерфейса. Итак, еще раз мы ожидаем, что испытания пройдут.
Это подразумевает, что для нашего открытого интерфейса, который, по-видимому, является стабильным, нам нужна четкая отслеживаемость, чтобы мы могли видеть, что каждый открытый метод тестируется.
Чтобы ответить на ваш явный вопрос: Unit Test для открытого интерфейса имеет значение.
отредактировано в ответном комментарии:
Тестирование частных методов? Да, мы должны, но если мы не должны что-то тестировать, то я бы пошел на компромисс. В конце концов, если общедоступные методы работают, могут ли эти ошибки в приватных вещах быть настолько важными? Прагматически, отток обычно происходит в личных вещах, вы усердно работаете, чтобы поддерживать свой общедоступный интерфейс, но если вещи, от которых вы зависите, могут измениться, личные вещи. В какой-то момент мы можем обнаружить, что поддержание внутренних тестов требует больших усилий. Это усилие хорошо потрачено?
источник
Модульные тесты должны быть частью более широкой стратегии тестирования. Я придерживаюсь этих принципов при выборе типов тестов для написания и когда:
Сосредоточьтесь на написании сквозных тестов. Вы покрываете больше кода за тест, чем с помощью модульных тестов, и, таким образом, получаете больше удовольствия от тестирования. Сделайте это автоматизированной валидацией вашей системы в целом.
Перейдите к написанию модульных тестов вокруг самородков сложной логики. Модульные тесты стоят своего веса в ситуациях, когда сквозные тесты было бы трудно отлаживать или громоздко писать для адекватного покрытия кода.
Подождите, пока API, с которым вы тестируете, не станет стабильным, чтобы написать тест любого типа. Вы хотите избежать рефакторинга как вашей реализации, так и ваших тестов.
У Роба Эштона есть хорошая статья на эту тему, из которой я черпал изложение принципов, изложенных выше.
источник
Я склонен придерживаться другого подхода к модульному тестированию, который, кажется, работает хорошо. Вместо того, чтобы думать о модульном тесте как о «тестировании некоторого поведения», я больше думаю о нем как о «спецификации, которой должен следовать мой код». Таким образом, вы можете в основном объявить, что объект должен вести себя определенным образом, и, учитывая, что вы предполагаете, что в другом месте вашей программы вы можете быть уверены, что он относительно свободен от ошибок.
Если вы пишете публичный API, это чрезвычайно ценно. Тем не менее, вам всегда понадобится хорошая доза комплексных интеграционных тестов, потому что приблизиться к 100% охвату модульных тестов, как правило, не стоит и пропустить то, что большинство сочло бы «непроверяемым» методами модульного тестирования (насмешка, и т.д)
источник