Вопросы к практикующим TDD

Читаю Кента Бека.

Насколько я понял предлагается следующее:

— Не проектировать архитектуру;
— Не писать чистый код;

— Вначале писать тесты;
— Потом писать работающий код, который не валит тесты.

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

Данный подход подкупает своей новизной (хотя речь идёт о 2003 годе).

Вопросы:

— Появится ли на самом деле архитектура или нет?
— Станет ли работающий код чистым в результате рефакторинга?

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

Насколько может усложнить и усложнит ли разработку неправильная точка начала разработки через тестирование? Например, начать разработку с кейса «Товар можно добавить в карзину» или с кейса «Администратор назначает роли пользователям» Сойдётся ли разработка чере TDD к моменту полного покрытия в одно и тоже или будут явные признаки тягтения к точке начала?

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Читаю Кента Бека.

Читайте — всего Кента Бека
А именно еще
Шаблоны реализации корпоративных приложений. (Implementation Patterns)

Экстремальное программирование (понятней станет откуда у «адйжайл» ноги растут)

В древней юности моей, мы ничего не знали о TDD.
Но как-то так получалось что треть кода на Си — это были «запускали» библиотек, objей — кусочков готового продукта. и с десяток батников, в которых вперемешку были вызовы make и вызов слинкованных запускалок и кусочков, с кучей тестовых параметров.

Об ООП мы тогда знали что наконец-то круть Smalltalk дойдет и до нас, в виде С++ - но уже тогда, подсистемы проектировали и писали — разделяя роли между ними, struct частенько имели указатели на функции, которым и передавался первым параметром указатель на структуру-владелицу, и проч. и т.д.

TDD — это не новое, даже не 2003го года. Это то что было у многих на уме — светлая голова Кента Бека выразила словами, простыми принципами.

понятней станет откуда у «адйжайл» ноги растут

Они растут совсем не из XP. XP только частный специфический случай Agile. Сами по себе принципы типа «не затыкаться на водопаде» были сформулированы ещё Бруксом, а обязательность тестов выросла ещё из самых правил военной приёмки, от людей, которые не верили ничему, кроме того, что сами видели.

Это то что было у многих на уме — светлая голова Кента Бека выразила словами, простыми принципами.

Ну да, а Apple придумала оконный интерфейс, планшеты, и вообще компьютеры.</mode="kidding">

Учите первоисточники, а не шумных эпигонов.

Сами по себе принципы типа «не затыкаться на водопаде» были сформулированы ещё Бруксом

«Не затыкаться на водопаде» было еще в первоночальной работе Ройса, от которой и пошел есть быть термин. Внимательнее с первоисточниками.

Ну да, а Apple придумала оконный интерфейс, планшеты, и вообще компьютеры.</mode="kidding">
Учите первоисточники, а не шумных эпигонов.

по теме, похоже, нечего сказать?

по теме, похоже, нечего сказать?

Я достаточно высказался по теме в предыдущих комментариях.

TDD — некорректная, обманная комбинация правильных частных подходов. В обычно описываемом виде она имеет смысл только для менеджеров и только для разработки типа «написал и забыл».

Подробнее я писал, например, тут: netch80.livejournal.com/17832.html

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

Правильнее всего обеспечить выделение доли времени на тесты и жёстко его соблюдать, покрывая тестами 1) все основные сценарии и применения (включая те, что вытекают из спецификаций — это уже BDD) и 2) все подозрительные с точки зрения программиста места и случаи (маргинальные значения параметров, внесценарные повторные вызовы методов, etc.)

Сколько времени — определяется по возможностям — но это не менее 20%, а в соседних ветках рекомендовали 50%. Этого должно гарантированно хватить на доведение до рабочего состояния. Ну и см. выше про архитектуру.

Это Вам не тут.

Что и требовалось доказать :)

Ваше намеренное игнорирование проблематики? Да, доказано.

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

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

Но вот архитектура юнита появляется вполне, ибо на плохую архитектуру очень сложно писать тесты.

Правильнее всего обеспечить выделение доли времени на тесты и жёстко его соблюдать, покрывая тестами 1) все основные сценарии и применения (включая те, что вытекают из спецификаций — это уже BDD) и 2) все подозрительные с точки зрения программиста места и случаи (маргинальные значения параметров, внесценарные повторные вызовы методов, etc.)

Ок 1 и 2 покрываем. А что не покрываем тестами? Ведь если останется ветка не покрытая тестами, то там возможна ошибка, то есть или ее должны проверять руками или ждать привет от того одного юзера который ею пользовался.

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

Архитектура чего? Всей системы или модуля?

Каждого уровня. И системы, и модуля. Разумеется, на каком-то уровне сам термин «архитектура» начинает терять смысл, сводясь к очевидному.

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

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

Ок 1 и 2 покрываем. А что не покрываем тестами?

А почему Вы спрашиваете? Разве я писал, что что-то не покрываем?

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

Тут у Вас сразу несколько сомнительных допущений. Давайте по порядку.

Во-первых, откуда ожидать появление этой ветки? Почему она будет? Если она не нужна ни для какого требования спецификации, то ей нет причины вообще существовать. Если же она существует, то отрабатывает какой-то сценарий согласно спецификации, а значит, на неё наверняка будут тесты в составе первого пакета (BDD).

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

Во-вторых, предположим, что есть какая-то ветка, которую не покрыли тестом. Почему тестеры и пользователи её не заметят (а потом кто-то один заметит)? Может, спецификация просто содержала ненужное?

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

Снова же если исходить из «сначала тесты», то появление такой ветки практически не возможно

Неверно. Оно было бы теоретически возможно, если бы следовали другому правилу — «пишите только тот код, который удовлетворяет тесты» (что само по себе — грубая ересь: писать надо тот код, который решает задачу по спецификации и является минимальным для удовлетворения теста, а иначе можно писать только кучу if-return для значений тестов). Но Вы это правило тут не упомянули, а упомянули зачем-то порядок тестов, который вообще это не решает. Можно написать вперёд тесты, потом код, а можно вперёд код, потом тесты — и код будет одинаковый, если программист в состоянии держать в голове задачу.

Вот если он не в состоянии удержать всё в голове (как правило, это потому, что язык такой, что вместо сущностей предметной области код переполнен геттерами-сеттерами и прочими бульдогами) — да, тесты являются средством сосредоточения на целевой задаче. Я этим регулярно пользуюсь: написал тест, убедился, что не работает, и вижу твёрдо сам себе стимул исправления и место для раскопок. Но это опять же не прямо реализуемый декларированный эффект метода, а его побочный эффект. И он никак не гарантирует появление минимально необходимого кода со всеми покрытыми ветками ни при начальной разработке под тест, ни при рефакторинге «под ключ».

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

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

Что-то я не особо понимаю вы за меня или за медведя? (За ТДД или против)

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

TDD — некорректная, обманная комбинация ...

В чем именно некорректность?

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

Сначала написан код. Теперь пишем тест.
На основании кода? Нет ибо тогда он не проверяет код, а описывает его, и если код с ошибкой, то ошибка будет и в описании.

На основании спеки. Тест прошел — все классно. Не прошел — надо переписывать код. Вопрос: Накуя мы писали код?

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

Попробую, но не знаю получится ли понятнее :)

Код — это формальная запись некоторого процесса (в общем модели). Для того чтобы его (код) написать надо сформировать эту модель. Желательно сформировать в формализованном виде, как пример ТДД-тесты/БДД-спеки.

Что-то я не особо понимаю вы за меня или за медведя? (За ТДД или против)

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

В чем именно некорректность?

В классическом TDD объявляется, что
1) пишутся тесты до кода
2) тесты должны быть проверены на то, что они не проходят
3) пишется код для их удовлетворения.

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

Чтобы допустить в принципе ситуацию, когда код меняется, надо допустить, если использовать правило «test first», что новые тесты соответствуют TDD, но старые — нет, часть тестов может работать и до новой разработки, и после. А это значит, что они уже нарушают этот принцип — их нельзя проверить на корректность той проверкой, что «тест до написания упал => он, вроде, правильный».

Поэтому, или вы доверяете корректности уже существующих тестов согласно их коду, но тогда правило «сначала тест должен упасть» вообще теряет смысл, или вы вводите другие методы контроля корректности тестов (в моём случае это инверсии тестов, когда проверяется нарушение выходных данных при заведомых отклонениях входных данных). А в этом случае уже пофиг, были написаны тесты до или после: это вопрос административного контроля качества покрытия тестами, но не собственно их выполнения.

Сначала написан код. Теперь пишем тест.
На основании кода? Нет ибо тогда он не проверяет код,

Чушь какая. Вот Вам пример кода:

-spec(group_pc_repr(list({any(),list()})) -> list({any(),list()})).
group_pc_repr(List) ->
    rec_group_pc_repr([], List).

-spec(rec_group_pc_repr(list(), list({any(),list()})) -> list({any(),list()})).
rec_group_pc_repr(Out, []) ->
    Out;
rec_group_pc_repr(Out, [{Tag, List1}, {Tag, List2} | Rest]) ->
    rec_group_pc_repr(Out, [{Tag, List1 ++ List2} | Rest]);
rec_group_pc_repr(Out, [{Tag, List} | Rest]) ->
    rec_group_pc_repr(Out ++ [{Tag, List}], Rest).

А вот несколько тестов:

        {"rec_group_pc_repr() merge 3",
            ?_assertMatch(
                [{k1,[a,b]},{k2,[c,d]}],
                ?M:rec_group_pc_repr([],
                    [{k1,[a]},{k1,[b]},{k2,[c]},{k2,[d]}]))},
        {"rec_group_pc_repr() merge 4",
            ?_assertMatch(
                [{k1,[a]},{k2,[b,c]},{k3,[d]}],
                ?M:rec_group_pc_repr([],
                    [{k1,[a]},{k2,[b]},{k2,[c]},{k3,[d]}]))}

И как же эти тесты, пардон, «описывают» код? Они фактически являются спецификацией пунктов поведения кода, как он должен вести себя на нескольких характерных ситуациях. (Тривиальные проверки типа пусто->пусто я здесь не показываю.)

Если же Вы мне тут собрались рассказывать, что «проверкой» кода является то, что при его отсутствии тест показывает нарушение выполнения, то см. выше.
Или представьте себе, что кто-то что-то нарушил в среде выполнения и код проверки (в данном случае _assertMatch) выдаёт всегда положительный результат. Что Ваша проверка тут покажет? Её удовлетворит любой код, при котором тестируемый метод вообще существует и, соответственно, его вызов не порождает исключения.

и если код с ошибкой, то ошибка будет и в описании.

Тест не делается под коду. Тест делается по тому, что он должен выполнять. Если у Вас такие сотрудники, что они в состоянии написать любую ересь, лишь бы она удовлетворила тест, и никто это не проверяет, то они Вам напишут, повторюсь, ровно код вида

multiply(0, 0) -> 0;
multiply(2, 0) -> 0;
multiply(2, 2) -> 4.

то есть удовлетворяющий заданные тесты и не более того.
И таким сотрудникам — не место в нормальной конторе, а если их никто не поймал за руку на ревью — то и их ПМ’у.

А если тесты пишутся по ожидаемому поведению, а код — для соответствия спецификации, то порядок написания кода и тестов не имеет значения. Лишь бы эта работа была выполнена.

На основании спеки. Тест прошел — все классно. Не прошел — надо переписывать код. Вопрос: Накуя мы писали код?

Для того, чтобы написанием понять, что же на самом деле надо было делать.
Это совершенно нормальная ситуация, особенно в таких случаях, когда неизвестно, какое из решений окажется оптимальным или вообще работающим (во взаимодействии с отвратительно документированными API, которых особенно много у MS, но и другие фирмы не сильно отстают).
Код пишется, потом оказывается, что метод некорректен, но требует незначительных поправок (например, передать и доработать по месту один параметр). По-Вашему, надо весь старый код выкинуть, написать тесты под новый, затем их удовлетворять. По-моему, достаточно переделок ровно настолько, чтобы поддержать это изменение.

Код — это формальная запись некоторого процесса (в общем модели). Для того чтобы его (код) написать надо сформировать эту модель. Желательно сформировать в формализованном виде, как пример ТДД-тесты/БДД-спеки.

Формализация в виде тестов даст ровно необходимость соответствия этим тестам и ничего сверх того.
Имея «модель» в виде f(0,0)=0, f(2,2)=4, Вы даже не можете сказать, что требовалось — сложение или умножение, и тем более — какая точность, скорость, диапазон входных значений, и так далее. Поэтому тесты не заменят спецификацию выполняемого, и Ваше «желательно» непригодно для практической реализации.
А если есть спецификация, то есть и потенциальная необходимость дополнить уже сделанное новыми тестами.

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

Каждое из первого и второго не допускает возможности его применения для уже существующего кода, что неизбежно в случае, когда происходит изменение спецификации к уже написанному.

Это как? Поведение должно было изменится, на что вы и написали тест, а оказалось что он проходит и без ваших изменений. Одно из 2:
1) Поведение уже было реализовано.

2) Ваш тест — гуано.

Чтобы допустить в принципе ситуацию, когда код меняется, надо допустить, если использовать правило «test first», что новые тесты соответствуют TDD, но старые — нет, часть тестов может работать и до новой разработки, и после.

Возможны 2 варианта (или их комбинации):
1) Прекрасный пример этого: ru.wikipedia.org/wiki/Демагогия

2) Вы не в курсе что о чем таки говорите.

Посему позволю себе наглость пропустить дальнейший текст и признать вас «правым во всем».

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

Вы в курсе, что на один модуль/функцию/метод/etc. может быть много тестов, и что изменение требований не обязательно ломает их всех?

Вы не в курсе что о чем таки говорите.

Что я в курсе, говорит практика.

Посему позволю себе наглость пропустить дальнейший текст и признать вас «правым во всем».

Только-только начали по делу говорить, как Вы слили. Жаль, я таки надеялся, что такой задор покажет и полезные результаты дискуссии.

Всем +1 за ответы-комментарии.

Ну смотря что подразумевается под архитектурой. Например вы скорее всего сразу определитесь на каком языке и платформе вы будете писать код, вы заранее знаете у вас веб приложение, или десктоп, или облачное, вы представляете какую базу данных использовать и т.д. — это ведь является частью архитектуры? =) Насколько я понял Кента — он подразумевает что все разработчики в вашей команде имеют большой опыт (true seniors) и в таком случае можно следовать red-green-refactor и получить нормальный код, иначе скорее всего результат будет не очень хорошим без архитектурных ограничений =)

Но по идее в процессе написания кода через тесты будет проявляться доменная модель и «слои». Ведь регистрация пользователя или поиск товара в конце концов вас приведет к одному и тому же — неким domain objects, некому persistence layer’у, некому представлению всего этого на экране. Но по своему опыту скажу что в последнее время я часто писал тесты после кода, ибо при написании системы from scratch часто надо проверить идею, или даже несколько идей одновременно и выбрать лучшую, а тесты могут замедлять эту проверку, особенно когда Assert написать сложнее, чем глянуть в базу, или в файл, или в консоль

Таки пользуйте BDD и будет вам счастье.

Посмотри еще на NCrunch — инструмент для continious testing. Меняет восприятие. Для меня стал практически незаменимым.

Чем он отличается от других средств continuous integration?

Нет, это не continuous integration, это continious testing. Он в фоне запускает тесты и по показывает какие проходят, а какие упали (цветными точками возле каждой линии кода). При чем даже без сохранения файла можно понять проходит ли тест. У них на сайте есть видео с примером: www.ncrunch.net

Я не силён в теории этих понятий, но если оно 1) постоянно само пускает тесты, 2) умеет прогонять через тесты новые коммиты, то это то, что я имел в виду.

Штука в том, что коммитить не нужно. Даже файл не нужно сохранять. Просто изменил что-либо в редакторе и тулза запускает тест, который покрывает код, в который внесены изменения. И все результаты видны в студии (это плагин для VS). Я слышал, что в RoR тоже есть что-то похожее.

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

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

Дело вкуса. Конечно, можно настроить запуск тестов вручную. Но тогда теряется вся прелесть инструмента. Просто запускать тесты умеет и Решарпер и сама студия.

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

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

не является ли командная разработка мифом?

не является.

Возможна ли командая разработка при использовании TDD?

возможна, чуть даже упрощается чем без.

как не дублировать в большой команде?

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

Я думаю в из >1 человека формальный код ревью поможет решить проблемы с дублированием кода. Ну либо можно выделить роль «архитектора» (хотя это не по Кенту Беку), который будет делать ревью и принимать архитектурные решения по ходу написания кода.

Вопросы:
— Появится ли на самом деле архитектура или нет?
— Станет ли работающий код чистым в результате рефакторинга?

Ответы в самой постановке задачи:

Насколько я понял предлагается следующее:
— Не проектировать архитектуру;
— Не писать чистый код;
Если архитектурой никто не занимался она не появится. Так и останется большая куча разных кусков сшитых «белыми нитками».
Если нет архитектуры то и рефачить нечего. Если «нечистый» код уже написан и тесты проходят то стимула его улучшать нет. Просто в итоге рядом с большой кучей спагетти-кода будет лежать куча таких-же запутанных тестов.

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

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

Вон сам Кент Бек всякое набрасывал недавно на эту тему

Разработка без архитектуры — это очень гениально, особенно потом копаться в таком коде...

Грубо говоря, оно получается так: Любая фича может быть припилена к любому сорц-файлу. Очень эротично. :)

И что же это за Архитектура такая что без нее никакого кода не написать?

Выкинули TDD, работаем по методологии http://пиши-код-блять.рф/

Насколько я понял предлагается следующее:
— Не проектировать архитектуру;
— Не писать чистый код;
оба пункта приписать up-front
— Вначале писать тесты;
— Потом писать работающий код, который не валит тесты.

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

Вопросы:
— Появится ли на самом деле архитектура или нет?
Да. Но об этом отдельным постом
— Станет ли работающий код чистым в результате рефакторинга?
да, при условии что выполняется третья часть мантры TDD — см. выше
— В книге всегда присутствует одна безальтернативная точка начала работы, некоторый один юзкейс, с которого всё и начинается, но на практике юзкейсов может быть десятки и все они будут перекрывать совершенно разыне предметные области. Но начинать ведь всё равно надо с чего-то одного? Или написать сразу все тесты которые покрывают все известные юзкейсы а потом уже пытаться их пройти?

Одна из основных идей подхода в том, чтобы получать максимум информации (инсайтов) одновременно от production кода и от тестов, регулярно перемещаясь между ними. Исходя из этого не стоит пытаться написать все тесты сразу — одного-двух будет достаточно. Остальные чтобы не путались в голове или не забыть можно записать на бумажку (как делает Бек в своих книгах), или еще удобно писать пустые падающие или @Ignore тесты, к которым возращаемся по мере имплементации кода для предыдущих.

Насколько может усложнить и усложнит ли разработку неправильная точка начала разработки через тестирование? Например, начать разработку с кейса «Товар можно добавить в карзину» или с кейса «Администратор назначает роли пользователям» Сойдётся ли разработка чере TDD к моменту полного покрытия в одно и тоже или будут явные признаки тягтения к точке начала?

Не усложнит совсем, ИМХО можно этим не париться. Если к моменту полного покрытия наличествуют эти самые смущающие признаки — самое время дорефакторить.

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

Но писать через TDD вообще весь код — неудобно, особенно когда задача сложная и оптимальный набор сущностей/интерфейсов получается уже в процессе коддинга, а не до него. Передергивает, когда вспоминаю времена, когда нужно было вообще все писать через TDD, хотя опыт был интересный.

ИМХО сначала нужно хорошо научиться писать все через TDD, а потом — набив руку — уже позволять себе выбирать TDD или пост-фактум тесты или вообще забить так как недостойно тестирование.

Да — задачи бывают разные. И требовать вообще все писать только через TDD — глупо.
Будут тесты написаны до, после или параллельно с реализацией — не так и принципиально. В TDD важно другое: сначала понимать что надо сделать — и только потом начинать кодить. И находить проблемы и нестыковки как можно раньше. На практике обычно получается «микс»:
— Начали писать тест.
— Оказалось что требование нечеткое или неоднозначное. Уточнили, поправили.
— Продолжили. Оказалось что в интерфейсе чего-то не хватает. Поправили интерфейс.
— Продолжили. Оказалось что непонятно какие типы данных вернет будущий код.
— Набросали заглушку для кода что бы попробовать тест.
— Оказалось что для теста нужен мок (заглушка) других объектов. Добавили.
— Тест вроде-бы готов. Пишем код.
— В процессе написания кода оказывается что так, как задумано в тесте, сделать не получится.
— Подумали. Поменяли тест. Дописали код.
— Запустили тесты. Не взлетело (красное). Починили код — тесты прошли (зеленое).
— Посмотрели покрытие — оказалось есть непокрытый код. Добавили тестов.
— Отдали на ревью — техлид сказал что слишком сложно и непонятно навернули.
— Зарефачили, разбили на кусочки, улучшили код, добавили комментариев в тесты.
— Запустили тесты — все прошло.
— Сбилдили, запустили все тесты в проекте — прошло.

— Вот теперь готово!

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

Тут еще важно покрытие тестами. Оно должно быть 100%. То-есть код должен делать ровно то, что проверяют тесты.

Тут еще важно покрытие тестами. Оно должно быть 100%.

Нереально. Всі делегати і аксессори в бінах прийдеться покрити і не тільки.

вы о чем вообще? какие бины?

Java Beans, судячи по всьому.

реально, но тупо и вредно. Но менеджерам обычно нравится.

Теоритично можливо, але тупо. І хто за це заплатить?

Заплатит тот, кто и за все остальное.

измерение покрытие процентами строк кода — это шарлатанство. инфа 100%

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

Шарлатанство потому что ничего не показывает, и приводит к батареям тестов типа

testNullReturnsNull

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

Ничего не показывает потому что если даже строчка показана как «пройдено» это еще не значит что там все ок. Скажем на пальцах:

if (coll == null || coll.isEmpty())

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

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

чтобы проверить чтобы не было реализовано чего-то лишнего

это как?

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

чтобы проверить чтобы не было реализовано чего-то лишнего

это как?

ну вы можете по юнит тестам сказать что делает код.

а то, что вы написали выше вообще никакого отношения к ТДД или написанию тестов не имеет отношения.

то что я написал относится к измерению покрытия тестов. TDD или нет — не суть.

к тестам это тоже никакого отношения не имеет.

значит кто-то потерялся :)

Наприклад спочатку пишеться тест на конкретний флов і саксесс кейс. Після цього пишеться код функціонала і перевіряється вищезгаданим тестом. Якщо все гуд — то копіпастом ковбасять інщі кейси і іксепшин кетчі. Після цього запускається плагін який підрахує код кавередж і підкаже які кейси не були покриті.

— Появится ли на самом деле архитектура или нет?

Це залежить від вашого рахітектора. Існують також інегрейшн тести які впадуть якщо хтось зробить регрешн.

— Станет ли работающий код чистым в результате рефакторинга?

Рефакторінг — невід’ємна частина TDD.

Насколько я понял предлагается следующее:
— Не проектировать архитектуру;
— Не писать чистый код;

...

Нет. Предлагается сначала получить работающий код и __способ проверки того что он код работает__, а потом уже __довести код до высокого уровня__. Хотя можно и забить на каком-то этапе, но по крайней мере у вас будет работающий функционал, а не куча УМЛ-ек.

— Появится ли на самом деле архитектура или нет?

Самозарождение архитектуры? Тогда скорее нет, чем да. Но ТДД способствует.

— Станет ли работающий код чистым в результате рефакторинга?

Да. Так как писать тесты на плохой код краене не веселое занятие. В общем-то, есть 2 варианта: хороший код или вы постепенно забьете на тесты (и ТДД).

Или написать сразу все тесты которые покрывают все известные юзкейсы а потом уже пытаться их пройти?

Тест — код; Тест — код ... Никакого сразу ВСЕ тесты, потом ВЕСЬ код!

Насколько может усложнить и усложнит ли разработку неправильная точка начала разработки через тестирование?

Не понял. Можно подробнее?

P.S.

анный подход подкупает своей новизной (хотя речь идёт о 2003 годе).

Скорее вторая половина 90-х. ТДД, кажись, появилось как часть ХР.

Скорее вторая половина 90-х

в мейнстрим кажется ушло где-то середина 2000х.

Да. Так как писать тесты на плохой код краене не веселое занятие. В общем-то, есть 2 варианта: хороший код или вы постепенно забьете на тесты (и ТДД).

вы не представляете себе как трудолюбивы и не притязательны некоторые члены нашей профессии.

Підписатись на коментарі