Как в TDD сначала писать тесты, если тестируемые функции не определены?
Если у вас ничего нет, вы не можете написать тест, потому что нечего тестировать. Мне это кажется очевидным, но сторонники TDD никогда не обращаются к нему. Чтобы написать тест, вы должны сначала решить, как выглядит метод или функция, которые вы собираетесь тестировать. Вы должны знать, какие параметры передать ему и что вы ожидаете получить обратно. Это то, что на первом месте, а НЕ тест. Тесты НИКОГДА не могут быть первыми. На первом месте стоит дизайн, который определяет, какие классы и методы будут существовать.
3 ответа
Верно, что для того, чтобы написать тест, автор теста должен сформировать некоторое представление о том, как тестовый код может взаимодействовать с тестируемой системой. В этом смысле концептуальный дизайн «на первом месте».
Однако разработка через тестирование (TDD) ценна, потому что это не (только) методология обеспечения качества. Это, прежде всего, быстрая обратная связь .
Хотя вы можете иметь в виду первоначальный дизайн, как только вы начнете писать тест, вы можете обнаружить, что этот дизайн не работает (или его неудобно использовать). Это часто случается, и вы должны немедленно изменить курс.
Цикл рефакторинга « красный-зеленый» предлагает модель для размышления о TDD. Каждый такой цикл может длиться минуту или две.
Таким образом, вы можете начать с первоначального дизайна, но затем корректировать его (или полностью переосмысливать) каждые две минуты.
никогда не рассматривается сторонниками TDD
Я не согласен. Это обсуждается во многих введениях в TDD. Это (и многое другое) обсуждается в двух хороших книгах: « Разработка на основе тестов на примере» Кента Бека и « Растущий объектно-ориентированный код на основе тестов» Ната Прайса и Стива Фримена .
Все наоборот.
Если вы пишете тест, который вызывает функцию, которая не существует, ваш набор тестов не работает, и вы получаете сообщение об ошибке, заставляющее вас определить эту функцию, точно так же, как написание любого другого теста заставляет вас написать реализацию.
Чтобы тесты были хорошими, не нужно запускать их. Но такого рода тесты не должны оставаться в вашем наборе тестов. Их иногда называют «лестничными тестами»: вам нужно написать их, чтобы начать работу, но они только инструментальные.
Обычно происходит то, что, как только этот тест проходит, вы делаете его неудачным, будучи более конкретным. Технически тест, который у вас получится, будет таким же, как если бы вы написали его постфактум, и на его написание не ушло больше времени, но во время этого процесса вы смогли запустить набор тестов один или несколько раз, так что проводить меньше времени в недееспособном состоянии, так сказать.
Я хотел бы добавить, что в вашем вопросе нет ничего ложного, но ваш вывод не следует исходной посылке: верно, что сначала идет спецификация, но нет ничего несовместимого с формализацией этой спецификации в тесте перед кодом написано. спецификация и тесты заставляют вас писать код. TDD - это постепенный способ формализации спецификации, который гарантирует, что спецификация всегда стоит на первом месте.
Чтобы написать тест, вы должны сначала решить, как выглядит метод или функция, которые вы собираетесь тестировать. Вы должны знать, какие параметры передать ему и что вы ожидаете получить обратно. Это то, что на первом месте, а НЕ тест. Тесты НИКОГДА не могут быть первыми. На первом месте стоит дизайн, который определяет, какие классы и методы будут существовать.
Не совсем верно (тоже не совсем неправильно - это сложно [tm])
Если вы посмотрите на первый пример в «Разработка через тестирование на примерах», вы увидите, что Бек не начинает с классов и методов. Он даже не начинает с теста.
Самое первое, что он создает, - это список «дел», где каждая запись в списке дел является представлением поведения (моя терминология, а не его). Итак, мы видим такие вещи, как
$5 + 10 CHF = $10 if rate is 2:1
В наши дни вы с большей вероятностью увидите эту идею, выраженную в виде тройки Хоара (Given/When/Then, Arrange/Act/Assert и т. Д.). Но у нас есть напоминание программисту о том, что нам нужна автоматическая проверка, которая измеряет результат сложения двух разных валют и подтверждает, что результат соответствует некоторой спецификации.
В своем упражнении в его список дел входит «более простой» тест, который он пытается выполнить первым.
$5 * 2 = $10
Тот же список задач также включает некоторые другие проблемы, связанные с дизайном, НЕ выраженные в тестовой форме. Кроме того, список растет по мере того, как он работает над проблемой.
В этом смысле испытание стоит на первом месте. Мы пишем тест на языке, понятном людям. Перевод теста на язык, понятный машине, придет позже.
На втором этапе, где мы описываем тест машине, все становится еще сложнее. Совершенно верно, что, разрабатывая тест, мы также разрабатываем протокол связи, который позволяет тесту измерять то, что делает производственный код. Таким образом, существует определенный объем коммуникационного дизайна, который происходит параллельно с «тестовым» дизайном.
Но даже здесь тест не определяет все классы, которые будут существовать, он только указывает, что ему нужно для выполнения измерения. Мы описываем фасад, но не уточняем, что находится за этим фасадом.
По мере того, как мы проектируем больше системы, может случиться так, что указанный фасад будет использоваться только тестами как способ взаимодействия с другим базовым дизайном производственного кода.
(Примечание: здесь я говорю классы для согласованности с вопросом и ранней литературой, взятой в основном из примеров на Smalltalk или Java. Не стесняйтесь заменять «функции» на «классы», если это делает вас более удобным.)
Самый распространенный случай - это то, что фасад - это производственный код; мы обычно не добавляем элементы в дизайн, пока у нас не появится неспекулятивная мотивация для них.
«Модульное тестирование» накладывает определенное напряжение на эти идеи - как вы можете написать модульный тест без предварительной разработки границ модуля?
Настоящий ответ - неудачный - Кент Бек не писал модульные тесты. Он написал «тесты для программистов» (термин, который позже был переработан) и назвал их модульными тестами.
Используя язык тестирования 1990-х годов (когда началась вся эта неразбериха), более подходящим термином, вероятно, будет «составные тесты».
У вас также есть «Лондонская школа», которая пыталась выяснить, как использовать TDD для определенного стиля дизайна; написание теста для этого стиля требует более сложного тестового фасада «впереди» (роли и интерфейсы, стабильные альтернативные реализации и т. д.).
Также стоит помнить об обстановке.
(Отказ от ответственности: это не то, что я видел из первых рук - подумайте «на основе реальных событий», а не «фактов»)
TDD (и его родительская идея «сначала протестировать» программирование в XP) выступают против «предварительного проектирования», в котором вы решаете, какой должна быть иерархия классов и отношения, и документируете их, прежде чем вы фактически сядете и начнете писать код.
Главный аргумент в том, что процесс проектирования требует более коротких циклов обратной связи; что мы не будем глубоко привержены конкретному дизайну, пока не получим много доказательств того, что он будет работать нормально.
Все это говорит о том, что да, TDD как метод работает намного лучше в руках того, кто уже хорошо разбирается в разработке программного обеспечения. Посмотри на Майкла Фезерса , мама, без рук!эпоха.
Нет никакой магии.