«Я не пишу юнит-тесты, потому что ...» — отговорки

http://java.dzone.com/articles/unit-test-excuses
  • Перевод
Я глубоко верю в методику TDD (разработка через тестирование), так как видел на практике пользу от неё. Она выводит разработку ПО на новый уровень качества и зрелости, хотя она до сих пор не стала повсеместно распространённой. Когда наступает момент выбора между функциональностью, временем и качеством, всегда страдает именно качество. Мы обычно не хотим потратить больше времени на тестирование и не хотим идти на уступки в количестве выпускаемой функциональности. Если вы не планировали использовать методику TDD с самого начала проекта, то потом очень трудно перейти на неё.

Все мы слышали множество оправданий, почему кто-то не использует TDD, но нигде нет лучшей подборки оправданий, собранных в одном месте, чем в книге "Прагматическое юнит-тестирование на Java с помощью JUnit" из серии "Прагматическая книжная полка". Я прочитал эту книгу несколько лет назад и подумал, что ни один ответственный разработчик после прочтения этой книги не останется без чувства, что юнит-тестирование — это один из самых важных аспектов работы разработчика.

Самая тревожная отговорка, которую я слышал — это "мой код слишком сложно тестировать". Этому может быть два объяснения. Одно — это большая часть вашего кода рисует UI (пользовательский интерфейс), а автоматизирование UI-тестов слишком сложно. Я соглашусь, что автоматизация тестирования UI — дело сложное (хотя и возможное), но для автоматизации должно быть сделано всё, что возможно: подумайте о регрессионных тестах. Если у вас есть полностью автоматизированный набор тестов, включая UI, вы всегда можете вносить новые изменения в код, пребывая в полной уверенности, что вы ничего не сломали.

Второе объяснение, почему ваш код слишком сложно тестировать — ваш дизайн слишком запутанный. Возможно, логика и UI-код слишком тесно связаны, и эта зависимость осложнит вашу жизнь, если у вас нет автоматического UI-теста. Вот тут как раз юнит-тестирование помогает создать хороший дизайн. Использовать JUnit очень просто, поэтому если мне только удастся выделить отдельный слой с логикой и писать для него тесты, мне удастся автоматически протестировать всю логику, которую когда-либо будет использовать UI. Что? У вас нет доменной модели? Тогда используйте заглушки (mock objects) — существует множество библиотек для этого.

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

  • Написание юнит-тестов занимает слишком много времени.
    Это отговорка номер один. Похоже, это следствие того, как информатику преподают. В большинстве случаев нас учат думать, что тестирование — это нечто, что случается в самом конце, а не в течение всего процесса.

    Книга "Прагматическое юнит-тестирование" пропагандирует модель «плати по ходу дела», согласно которой следует писать юнит-тесты с самого начала, вместе с тем, как вы пишите код, и тогда у вас не будет этого нервного периода в конце, когда вы в спешке будете пытаться впихнуть все ваши юнит-тесты.

    Так или иначе, если вы не пишите тесты с самого начала, как вы тогда проверяете, что код работает так, как задумано? Вы запускаете его вручную? Не будет ли тогда разумным потратить немного времени от ручного тестирования на написание JUnit-теста? Ведь вам придётся запустить этот кусочек кода ещё не раз в течение разработки проекта.

    На самом деле вас ожидает гораздо больше разных временных потерь, если вы не пишите юнит-тестов. Вы потратите время на дебаггинг, пытаясь понять, почему что-то не работает. Или вам придётся рано или поздно подрефакторить ваш код, после чего вы обнаружите, что после рефакторинга ничего не работает. Если у вас есть написанные юнит-тесты, у вас есть основа для уверенности.
  • Запуск юнит-тестов занимает слишком много времени
    Признаю, тесты, которые используют внешние зависимости или работают с пользовательским интерфейсом, могут действительно долго работать. Но предполагается вообще-то, что у вас должно быть несколько уровней тестирования. Уровень юнит-тестов должен запускаться быстро. Также у вас может быть некий уровень интеграционных тестов, которые тоже должны запускаться без ощутимых временных потерь — просто запускайте их не так часто, например, каждую ночь. Но при этом не забывайте про юнит-тесты — они должны быть настолько быстрыми, чтобы стать естественной частью процесса разработки.
  • Это не моя работа — тестировать код
    Я не представляю, в каком состоянии разработчик должен находиться, чтобы решить, что он может просто кидать готовый код через стенку. Если бы название вашей специальности было «тупо Кодер», то может, эта отговорка ещё бы прокатила. Но ваша работа — разрабатывать работающее ПО, а значит, у вас должно быть какое-то основание заявлять, что ваш код — работающий. Если тестовый отдел считает непростым найти ошибку в вашем коде, это будет творить чудеса с вашей репутацией.
  • Я не могу протестировать код, потому что я точно не знаю, как он должен работать
    На это сложно реагировать без недоверия. Если вы точно не знаете, как должен работать код, как вы вообще могли начать его писать? Сперва нужно понять требования.


В этой книге перечислены и другие отговорки. но эти — основные. А какие отговорки слышали вы?

Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 225
  • +20
    Мне приходилось слышать банальное «Лень»
    • 0
      банальный пример: изменилась форма 2НДФЛ разработчики прислали новую конфигурацию с ее реализацией, как написать такой тес чтобы он определил что какое то из полей заполняется не верно, при том что алгоритм изменился?
      • +6
        Если изменился алгоритм основной функциональности, нужно изменить алгоритм теста. Звучит по кэповски, но это так)
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          «поэтому ушел» — правильно сделали. Если организация не поддерживает пути разработки, кроме «быстро и за копейки» — нахрена там работать?
          • +3
            причем тут вообще заказчики? все эти штуки — паттерны вместе с юнит-тестами, разработчики придумали для себя, чтобы быстрее работалось. заказчикам про них вовсе знать не обязательно
            • +2
              А мне казалось, что основное их назначение упрощение и ускорение не собственно разработки, а дальнейшей поддержки и развития.
              • –2
                одно другому не мешает
                • +3
                  Мешает.
                  Куча действий требуют затрат СЕЙЧАС, а пользу приносят ПОТОМ.
                  Это инвестиции, и компании, которые не готовы инвестировать в свои процессы, всегда находятся в хаотично-болотистом состоянии.

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

                      Если понимания значимости той или иной инвестиции нет, то и возможности решить возникшие псевдопроблемы нет.
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  — юнит тесты — часть реализации, отдельно время не закладывается. приемочное тестирование — другое дело.
                  — так и работаем

                  п.с. чтобы можно было писать чаще, глупости не надо было писать вам.
                  • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              А Лень как известно — двигатель прогресса!!! )))

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

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

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

              4. Юнит тесты сложны в поддержке. Код меняется по мере разработки — тонны юнитов летят в корзину. Если Вы делаете одно простое изменение в коде, Вам нужно перелопатить десяток тестов.

              Безусловная полезность юнитов и TDD является в том, что самого начала заставляет быдлокодеров заботиться о компонентной модели кода и декомпозиции функционала.
              • 0
                Тесты — суть выражение функциональных спецификаций. Если в тесте не отражены (явно или же очевидным образом) какие-то условия, считайте что на них нет постановки. В самом деле, постановка может быть не полной. Но в этом виновата лишь ваша лень — при чем тут TDD? :) Кстати, тут могут быть полезны вот такие феньки, которые выводят лейаут теста на «человеческом» языке — обратно, в виде спецификации.

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

                В процессе выполнения теста создаются идеальные условия для дебага.

                Если одно и то же изменение в коде вызывает каскадное изменение других тестов, это является сигналом о сильной связанности — т.е. ваша система тестов попросту плохо спроектирована. (сюрприз, чтобы тесты было легко поддерживать, их тоже необходимо вдумчиво проектировать — так же тщательно как и любой другой код. поэтому как раз-таки для «быдлокодеров» от ни нет ни какой пользы).
            • +9
              Я не пишу юнит тесты — потому что практически не возможно автоматически пользоваться ими в гетерогенной с точки зрения устройств среде. я могу запустить проверку как правило только на эмуляторе, я не имею возможно автоматически продеплоймить и запустить на всех целевых устройствах.

              Я не пишу юнит тесты — потому что они не работают (без собственно реализации) в гетерогенной с точки зрения языков программирования среде. Типичный пример — код с тесным взаимодействием классов и функция на языках c/c++, java и javascript, причем javascritp во внутреннем браузере который так же на писан на c/++ и java.

              Я не пишу юнит тесты — потому что более существенная часть времени тратиться на баги которые не могут быть (или это крайне сложно) обнаружены в автоматическом режим. Типичные примеры — после изменения скорости движения у главного героя проскальзывают ноги, плашка под полем ввода сдвинута на 2 пикселя влево по сравнению с redlines, opengl эффект затухания меню стал выглядеть некрасиво, после перевода картинка в 8 бит градиенты стали выглядеть хуже.

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

              • +25
                вы не пишете юнит-тесты, потому что не понимаете, что это такое и для чего оно нужно, а вовсе не потому, что вы крутой разработчик игр
                • 0
                  Не для всего есть клевые методы тестирования.
                • +4
                  1) юнит тесты могут работать в гетерогенной среде, я вас в этом уверяю, т.к. я это делал
                  2) юнит тесты могут работать даже в смеси javascript/java/c++, просто надо правильно дизайнить систему, разделять эти уровни, делать их тестируемыми по отдельности, делать дизайн всей системы mockable, писать эти самые моки и тестировать end-to-end
                  3) именно поэтому надо писать юнит тесты — чтобы не тратить время на баги, которые юнит тестами *могут* быть обнаружены.
                  4) а вот это уже просто потому, что вы, вероятно, не очень опытный программист — это приходит со временем, со сданными (и заваленными!) проектами, с опытом.

                  Overall, мне кажется, что в вас играет некий юношеский максимализм — «Юнит-тесты не нужны, потому что мои задачи для них слишком сложны». Это полностью повторяет первую отговорку, приведенную топиккастером.

                  Q.E.D.
                  • 0
                    Было бы круто пару примеров привести.
                    • 0
                      примеров чего?
                      • 0
                        1) юнит тесты могут работать в гетерогенной среде, я вас в этом уверяю, т.к. я это делал
                        • 0
                          Вообще это сильно зависит от характера приложений. Но общий принцип один и тот же – делать mockable как можно больше частей кода, чтобы можно было отдельно протистировать взаимодействие как таковое (это сложно, но не очень сложно), и отдельно — функциональность компонент.

                          Ну и разумеется, если архитектура позволяет (читай: дизайнилось изначально с расчетом на автоматизированное тестирование), часто можно в режиме big test поднять небольшой тестовый environment даже на нескольких машинах, сервер, клиент, прогнать batch-request, посмотреть, что получится и сравнить с тем, что должно.

                          Вот с чем я совершенно не сталкивался — это тестирование браузерных приложений. Знаю, что это как-то делается, но поскольку UI я не занимаюсь ни в каком виде, с этим я не работал.
                • +1
                  Я чаще всего слышу отговорку такого свойства: «Если я напишу тесты, кто напишет тесты на тесты». То есть, есть ли гарантия, что тесты работают правильно? Я сам много раз сталкивался с ситуациями, когда сами тесты содержали ошибки; иногда крошечная механическая опечатка в тесте из серии

                  for(i=0; i<42; ++i); {units[i]->test_yourself()}

                  может создать ложную уверенность, что всё работает отлично.
                  • +9
                    Двойная проверка. Вероятность того, что одна и та же ошибка будет допущена в 2-х местах (и в тестах и в коде) — во много крат ниже.
                    • –1
                      Во-первых, а почему вы решили остановиться на двойной? Может лучше тройная? Согласитесь, что даже десятирная — не панацея. Причём, — внимание, — все следующие проверки не проверяют код! Они проверяют проверяльщиков. Если единственная первая проверка что-то упустила, все остальные не помогут.

                      Во-вторых, почему вы говорите про одну и ту же ошибку? Ошибки могут быть разные. Достаточно того, чтобы одна ошибка скрывала другую. Самый простой вариант, тест просто не тестирует некий аспект, скажем, не пробует везде подставить нули и не детектирует деление на ноль, которое выползает в реальной жизни.
                      • –1
                        >>Во-первых, а почему вы решили остановиться на двойной?

                        Потому что есть 2 стороны: наша система (программа) и внешний мир (пользователь или другая система). С помощью тестов мы эмулируем внешний мир. Третьей стороны нет. Была бы третья — можно было бы делать тройную проверку.

                        Алгоритм «внешнего мира» не является полным аналогом алгоритма системы.

                        >>Достаточно того, чтобы одна ошибка скрывала другую.

                        Бывает и такое. Здесь важна вероятность. По вероятности отпишу ниже.

                        Лично мне тесты помогают при рефакторинге. Хочу улучшить код (привести к ) — а он потом перестает работать правильно (какая-нибудь мелочь). Вот такие мелочи тесты находят быстро.
                        • 0
                          Принцип Паретто: 20% затрат, 80% результата.
                          И следующая за этим принципом приоритезация задач.

                          Когда (и ЕСЛИ) у Вас будет абсолютно свободное время, Вы можете сделать тройную, четверную, и какую угодно проверку. Но начинать всё равно надо с наиболее приоритетного уровня проверки, то есть первого.
                          • –1
                            Комментарии из серии «книгу не читал, но хочу заметить». CRAP наше все.
                            • 0
                              Ну, если быть точнее, то комментарий из серии «Я неоднократно строила процессы контроля качества кода в крупных и маленьких компаниях, и считаю, что приоритезация задач — залог успеха».

                              В среднем, 3-5% тестов приносят 98% покрытие кода.
                              • +2
                                Опять какие-то значения с потолка.
                        • +1
                          во-скока — во-скока?!
                          • +4
                            Во много крат. Не в 2 раза, а именно во много крат. Парадокс, да?

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

                            Если добавить тесты, то в них так-же будет 1 ошибка (так-же 100 действий).

                            Какова вероятность того, что ошибка будет в одном и том-же месте и в тестах и в программе (речь о машинальной ошибке)? Получается 1 из 10000, верно? Другими словами качество кода повысится в 100 раз, хотя времени затратим только в 2 раза больше.

                            Поправьте меня, если я ошибся.
                            • +1
                              Парадокса нет. Всё зависит от того, как вы меряете качество кода.
                              Без тестов ваш код был на 99% правильным, с тестами — на 99.99%. Качество выросло всего на 1 процент, а времени потрачено в 2 раза больше.
                              • +2
                                — Какова вероятность, что выйдя на улицу вы встретите динозавра?

                                Вы рассуждаете как некоторые женщины:
                                — Нуу, 50/50 — либо встречу, либо не встречу!
                                • +1
                                  Всё зависит от точки зрения, вас интересует вероятность наличия ошибки, собеседника — вероятность её отсутствия :) Увеличивая одну в два раза, мы не уменьшаем другую в два раза. Анекдот про 50/50 не уместен тут.
                                  • –1
                                    Чего? Серьёзно?! Ё-моё, вся теория вероятности коту под хвост.

                                    Если вероятность события A = 0.7, то вероятность того, что событие A не случится = 1 — 0.7 = 0.3

                                    Вы сами внимательно прочитали комментарий, который вы поддерживаете?
                                    Код на «99% правильный», стал на «99.99%» правильным. Это вообще чего такое?
                                    Эти цифры взяты из каких натуральных соображений?

                                    Код может быть правильным и на 100%, но при его изменении существует достаточно большая вероятность неверного конечного результата. Тесты же позволяют компенсировать эту вероятность, отчего общая вероятность ошибки становится (по доказанной теории вероятности) A*B (вероятность возникновения 2х параллельных событий), а не A+0.99% (вероятность ошибки в коде + какая-то-с-потолка-взятая-процентность).

                                    • +3
                                      Всё согласно теорверу:
                                      Если вероятность отсутствия ошибки 0.99, то вероятность её наличия 0.01. Уменьшаем вероятность наличия ошибки в 100 раз — получаем 0.0001, не будете же вы утверждать, что вероятность отсутствия ошибки стала 99 в таком случае (0.99*100)? Правильно, вероятность отсутствия ошибки увеличилась всего в (1-0.0001)/0.99=1,01 раза или на 1%.

                                      Каким-то образом оценили вероятное количество ошибок в коде (есть методики, например намеренное введение ошибок в код, с последующим его анализом другими программистами/тестировщиками, соотношение заранее известных и неизвестных ошибок среди найденных ими позволяет делать выводы о вероятном оставшемся количестве неизвестных) в 1% от всего кода. Покрыли код тестами на 100%, оценили также количество ошибок в 1% от количества кода теста. Есть, имхо, основания утверждать, что вероятное количество ошибок в коде уменьшилось в 100 раз с 1% до 0.01%. Возможно не точно, теорию ошибок и т. п. не изучал, но натуральные соображения такие.

                                      А в том, что основное назначение тестов не повышение вероятности отсутствия необнаруженных ошибок в существующем коде, а уменьшение вероятности образования новых необнаруженных ошибок при изменении кода, я полностью с вами согласен. TDD же, как я её понял, базируется на том, что код надо покрывать тестами ещё до его написания и, соответственно, уменьшать вероятность появления необнаруженных ошибок с самого начала, условно считая, что написание кода является изменением пустого кода :)
                                    • 0
                                      Коль, перечитай тервер.
                                      • 0
                                        Я его помню. И есть конкретное правило: если в момент времени вероятность возникновения события A равна p1 и события B равна p2, и события равновероятны, то общая вероятность возникновения этих событий равна p1*p2 (например, подбрасывание 2х монет и выпадение на обоих решки, 0.5*0.5 = 0.25). Это же не высшая математика, всё просто. Поэтому, если при изменении кода вероятность возникновения ошибки равна p1, в то же время вероятность ошибки в тесте на этот код равна p2, всё абсолютно аналогично. Вопрос ведь не в том «какова вероятность наличия ошибки в коде при наличии теста», а «какова вероятность ошибки и к воде и в тесте на этот код».
                                        • 0
                                          Попробуй посчитать вероятность возникновения ошибки по другому: у тебя в программном модуле есть N методом и в каждом из них ты можешь сделать ошибку с вероятностью, пропорциональной количеству строчек кода, реализующих бизнес-логику. Вероятность допустить ошибку является композицией от вероятностей сделать ошибку в этих N методах. В случае TDD ты пишешь N тестов, чтобы покрыть функциональность методов (при правильном применении ТДД количество тестов будет соответствовать количеству методов, при неправильном — количество тестов будет больше, чем количество методов). Соответственно, вероятность возникновения ошибок в тестах считается так же. Так-как функциональность методов пишется после создания тестов, то вероятность возникновения первичной ошибки в тестах считается первичной, то при возникновении ошибки в тесте реализация уже будет неправильной. По этому вероятность ошибки реализации программы в целом будет считаться как сумма вероятностей от ошибки в тесте и одновременной ошибки и в тесте и в реализации.

                                          Соответственно, при увеличении строк кода в тесте и увеличении N вероятность ошибки увеличивается. Откуда были получены эти «в разы» мне, лично, непонятно.
                                • 0
                                  >>Без тестов ваш код был на 99% правильным, с тестами — на 99.99%. Качество выросло всего на 1 процент, а времени потрачено в 2 раза больше.

                                  Совершенно верно. Нужно только решить насколько критичен этот 1% для конкретного проекта. Если 1% ошибок выльется в процент потерянных денег — то весьма критично.
                                • 0
                                  Прочитайте пожалуйста: habrahabr.ru/blogs/tdd/112685/#comment_3611572
                            • +9
                              По TDD — сначала тест не должен пройти — он должен быть красным. После того, как вы добавите код, запустите еще раз тест — он должен быть успешен. Таким образом если у вас он до написания кода зеленый, или после написания кода красный — значит тест не правильный (при условии что код верен).
                              • 0
                                Вот ответ на ваш вопрос: habrahabr.ru/blogs/tdd/112851/
                                • 0
                                  Насколько я помню, одно из первых правил написания тестов — «make it fail».
                                  Т.е. при написании теста нам нужно добиться обоих случаев — и чтобы он выполнялся, и чтобы он валился.

                                  Но ошибки в тестах, тем не менее никто не отменял. И частичным тестированием юнит-тестов будут заниматься интеграционные (к которым так же применяем правило «make it fail»).
                                • +3
                                  Давно уже перешёл на TDD, и очень доволен. Но, к сожалению, не всех могу убедить использовать юнит тестирование. Чаще всего отговорки: нет у меня времени писать тесты, да и не помогут они.
                                  • +4
                                    TDD абсолютно не панацея. нужно найти баланс между следованию ТДД во всем и построением архитектуры приложения изначально.
                                    • +2
                                      Вообще TDD это действительно не панацея, а часть методологии XP — но там upfront построение архитектуры это просто выброшенное в унитаз время, чем и является.
                                      Я прошел горький опыт от проектирования систем upfront, когда пол года постоянной работы трех архитекторов только над проектированием вылился в бешенное разочарования из за изменений требований на середине двух годичной разработки.
                                      Проект пришлось переписывать заново, в этот раз на проектирование upfront потратили две недели ровно — даль итеративный процесс разработки архитектуры. Проект получилися очень простым, очень maintainable и все, включая архитекторов, просто в восторге от такого подхода.
                                      Но, без TDD, без итераций, без быстрого feedback'а и понимания, что надо приветствовать изменения, а не отвергать — без всего этого не возможен был бы успех.
                                      • –2
                                        заметьте, я не утверждал, что ТДД зло и не используйте его. Я лишь говорил, что нужен баланс. Вы в своем случае его нашли и получился отличный проект. Если следовать чисто ТДД методикам, то получится тоже великое разочарование по той причине, что у вас порсто не будет архитектуры вменяемой
                                        • +4
                                          «Если следовать чисто ТДД методикам, то получится тоже великое разочарование по той причине, что у вас порсто не будет архитектуры вменяемой»
                                          Непонимаю, откуда вы берете это утверждение? Почему вы считаете, что если следовать TDD у вас не будет архитектуры? Просто в голове не укладывается, чем написания тестов перед реальным кодом может помешать нормальной архитектуре?
                                          Наоборот, если идти TDD way эволюционировать архитектуру намного проще, чем без TDD, ибо TDD требует движение маленькик шагами, когда после вашего каждого изменения вы уверены, что проект будет работать. При стандартном изменении архитектуры все меняется большим скопом, потом долго и упорно тестируется и правяться (или не правяться) тесты.
                                  • +6
                                    Не смотря на то как близок дедлайн всегда пишу юнит-тесты, ибо без них просто не могу передать код в техподдержку, совесть не позволяет. И в 90% случаев это позволяет выявить ошибки еще до сдачи кода тестировщикам. Иногда даже приходится дописывать юнит-тесты за своими коллегами, ибо многие не понимают важность этой задачи.
                                    • +2
                                      > «тупо Кодер»

                                      Называйте вещи своими именами, чего уж там. Зачем эвфемизмы выдумывать?
                                      • 0
                                        Когда спецификация заморожена, то тесты могут покрывать спецификацию. А если функциональность постоянно меняется, но приходится менять логику и тесты. И в тестах появляются баги, так что хоть пиши тесты для тестов.
                                        • 0
                                          тест == спецификация. меняются требования, меняется тест, меняется логика — в такой последовательности.
                                          • +6
                                            Меняется функциональность -> меняется тест -> код переписывается чтобы этот тест «прошел».

                                            Частенько, из тестов проще понять что должен делать код, чем из самого кода.
                                            Равно как, и сначала переписать тесты под новую спецификацию, бывает проще чем сразу править код.
                                            • –2
                                              Бывает так что тест сильно зависит от логики, поэтому я не могу написать тест, пока не определюсь с названиями методов, интерфейсов. А эти названия, структуры приходят во время написания логики.
                                              • +5
                                                в этом и специфика тдд. что когда вы пишите тест вы продумываете сразу названия методов которые он будет тестировать, интерфейсы и тп.
                                                • 0
                                                  Я не знаю как в совсем тру TDD. Но если я начинаю писать какой то код, то последовательность такая:
                                                  1. Костяк системы — внешнее API, классы модели, классы представления, интерфейсы сервисов. Все это почти без внутренностей.
                                                  2. Тесты фиксирующие будущее поведение системы.
                                                  3. Наполняю вещи из пункта 1 кодом, пишу внутренние служебные классики и тесты для них.

                                                  Подход итеративный. Т.е. когда мы спускаемся вниз к внутренним классам, то для них эти 1 шага повторяются.
                                            • +12
                                              я не пишу юнит тесты, потому что в 1с это нереально
                                              • +1
                                                Почему же нереально?
                                                www.pcmag.ru/solutions/sub_detail.php?ID=6280&SUB_PAGE=0
                                                :)
                                                • +10
                                                  Уважаемый посетитель!

                                                  Мы благодарны за интерес к сайту pcmag.ru, однако, как показывает статистика, 71% посетителей, приходящих по ссылке с сайта habrahabr.ru, покидает нас спустя 5-10 с.

                                                  Заботясь о вашем комфорте и удобстве серфинга, мы хотели бы предложить ряд ссылок, которые, согласно статистическим данным, могли бы быть более интересны:

                                                  «Жучарко с сяжками и скаковыми ногами»
                                                  «Дом-2 — официальный сайт реалити-шоу на канале ТНТ»
                                                  «Мой мир@Mail.Ru»
                                                  «РАНЕТКИ — официальный сайт»/
                                                  «Comedy Club Официальный сайт»
                                                  Для продолжения сеанса работы и перехода на сайт, вам достаточно повторно кликнуть по кнопке Go (или «Переход» для русских версий популярных браузеров) или перейти в строку адреса и нажать Enter.

                                                  Если у вас имеются вопросы и пожелания, вы можете связаться с администрацией сайта по адресу newsdesk@pcmag.ru.
                                                  • +1
                                                    Решение есть на сайте ранеток.
                                                    • +1
                                                      а меня больше журчатко заинтересовало =))
                                                    • 0
                                                      Ну, я думаю, не только программисты знают, как зайти на сайт, не оставив referer? А?
                                                      • 0
                                                        А с администрацией надо бы связаться и научить любить Хабр…
                                                      • 0
                                                        Интересно, кстати, чеи это вызвано? :)
                                                        • 0
                                                          Неоднократным хабраэффектом? :)
                                                      • +3
                                                        Из этого я понял только то, что PCMAG делают идиоты.
                                                      • 0
                                                        Проблема в том, что число вариантов слишком велико, взять тот же расчет себестоимости/партионный учет/РАУЗ, которые настраиваются десятками параметров. чтобы подготовить тестовые данные, охватывающие все случаи, уйдет не один месяц.
                                                        (а потом еще нужно будет написать тесты для проверки правильности работы тестов и т.д.)
                                                        • +1
                                                          Незнаю по поводу 1С, но порадовала отмазка про тестовые данные.
                                                          Вы именно сначало должны их подготовить, а уж потом писать расчеты. При чем необязательно сразу подготавливать огромный набор, в TDD процесс итеративный.
                                                          • 0
                                                            вот есть типовая конфигурация. (более 40 мб кода в ТХТ). нам нужно сделать определенную доработку, причем таким образом, чтобы обновление этой типовой не сильно затруднялось. + прикрутить каким-то образом туда еще программную часть для юнит-тестирования. + вбить данные, которых для моделирования реальных ситуаций учета нужно реально много (десятки и сотни документов/элементов справочников для проверки чего-то одного. + эталонные результаты выполнения, которые вообще непонятно, как хранить)
                                                            • +2
                                                              Ну в данном случае это класический пример legacy кода — где либо забиваем на все, либо на доработки пишем unit test'ы, но только там, где это принесет бенефиты.

                                                              Тут опять таки нужен баланс — есть так называемая теория technology debt, то есть когда изменения вносятся adhoc и забивают на всякие тесты — недоработки в тестировании или shortcut'ы всякие увеличивают technology debt, который придется когда нибудь платить. Если technology debt изменения конфигурации 1С совершенно несравним с деланием всего правильно и в дальнейшем исправления все этого technology debt все равно в разы меньше effort'ов на создания тестов — тогда да, в топку TDD в данном случае.
                                                          • 0
                                                            а как правильность расчетов проверяется сейчас?
                                                            • 0
                                                              обработка, которая на входе имеет документ (или какие прочие данные) и выдает результат выполнения операции над ним
                                                    • +2
                                                      юнит-тестирование помогает создать хороший дизайн.

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

                                                      Бывалый программист говорит, что и так всё знает («лень») и спихивает всё на тестеров (сразу заметно, кто плодит больше багов и отлаживает по F5).

                                                      Eсли команда примет решение (писать тесты), отговорки должны быть неуместны имхо.
                                                      • 0
                                                        Очень часто, что из коммерческих соображений, в списке «время», «функциональность», «качество», дл компании качество на последнем месте. например важно выйти с новой верисей раньше конкурентов
                                                        • +3
                                                          «Это отговорка номер один.»
                                                          • +3
                                                            Отговорки — удел программистов, а решение сколько времени уделять на тестирование, сколько тестеров держать — удел начальства.
                                                            Фирма должна делать деньги. Хороший софт — не самоцель, а средство.
                                                            Я сам пишу как раз юнит тесты :)

                                                            Но время на написание юнит тестов и количество тестеров в команде — это в конце концов бизнес решения.
                                                            Они могут быть ошибочными (если из за плохого качества клиенты откажутся от софта), или правильные (если через месяц выпустили следующую версию с исправлениями, но конкурентов опередили), но это бизнес решения
                                                            • +3
                                                              Я к тому, что время сэкономленное на тестах часто уходит на унылый дебуггинг в поисках ошибок.
                                                              Это про первую версию софта.

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

                                                              Конечно, это не относится к случаю, когда за 2 выходных нужно изготовить прототип системы (впрочем базовые тесты и тут помогут).
                                                              • +1
                                                                Пусть начальство решает по тестерам, а ведущий программист по тому, будут модульные тесты или нет, исходя из поставленных задач.
                                                                Скажем, алгоритм быстрой сортировки быстрее и правильнее проверить тестом, нежели отладочным консольным приложением или, что ещё хуже, в реальном приложении (убедиться, что всё будет хорошо в программе, стоит конечно, но не отлаживать таким образом).
                                                            • 0
                                                              да можно выйти раньше конкурентов скажем на неделю, а потом отгрести от пользователей за баги, недоделки и тд и тп. Я думаю что лучше выпустить софт позже на наделю, но качественней чем у конкурентов. Ну а если конкуренты вышли на неделю раньше с тем же качеством что и у вас, то тут стоит задуматься вообще об эффективности работы компании
                                                              • +4
                                                                Это бизнес решения. Да, они должны приниматься осознанно, но ситуация когда надо выйти с версией пораньше, сделать пресс рилиз о новой функциональности во время гораздо важнее того качества, которое получят пользователи.
                                                                Печально? Да.
                                                                Но это реальности
                                                                • +1
                                                                  Кто первый встал того и тапки. Не видел еще пользователей с вилами у дверей офиса. Обычно все ограничивается потоками лучей ненависти по каналам связи с общественностью, но кому до этого дело когда идет экспоненциальный рост выручки?
                                                            • 0
                                                              Я не мою руки каждый раз перед едой, потому что…
                                                              • +2
                                                                «Я не пишу юнит-тесты, потому что ...» хочу потерять работу.
                                                                В моей компании, это так.
                                                                • +8
                                                                  Ну и давайте рассмотрим временные потери на TDD:

                                                                  Вот у меня был программист. В общем-то неплохой профессионал. Даёшь техническое задание — пишет код. Никаких юнит-тестов, никакого continuous integration. Тестирование модульное — интеграционные тесты, регрессионные тесты. Написание кода занимает около 30%, 70% — итеративная доработка по регрессам.

                                                                  Техническое задание склонно к мутация ибо бизнес-задачи. В случае изменения параметров ТЗ фильтруем список для регрессионного тестирования, шерстим интеграционные тесты. Трудозатраты: 1 программист, 1 тестировщик, 1 продакт.

                                                                  Попробуем ввести TDD. Выясняется, что ТЗ нужно вначале декомпозировать на требования, понятные программисту, написать хотя бы подробную спецификацию продукта, иначе непонятно, как писать функциональные требования. Далее выясняется, что перед тем, как писать тесты неплохо бы описать архитектуру раза в два точнее. Ок. Вводим роль архитектора, который следит за мутацией требований и поддерживает консистентность спецификаций. Кто у нас будет архитектором? Естественно — самый мудрый дядька. На каждый модуль начинаем писать тесты. Написали, посмотрели — слишком много параметров. Надо декомпозировать. Декомпозировали — слишком много тестов. Кого садим писать тесты? Джуниора. Посадили, написали. Начали кодить. Требования дополнились. Спецификации поменялись, тесты поменялись, код рефакторим. Написали, начали регрессионное тестирование. Обнаруживаем баги — чёрт! — багина спецификацию. Значит надо тестировать спецификацию. Кто будет тестирвоать спецификацию? Тест аналитик. Вводим роль. Наконец-то полностью прокатываем процесс, после чего видим, что регрессионное тестирование опять таки занимает 70% времени.

                                                                  Подбиваем трудозатраты:

                                                                  0.3 архитектора, 0.1 тест аналитика, 0.7 джуниора, 1 программист, 1 тестировщик
                                                                  Время проекта выросло на 40% (потому что добавились точки синхронизации архитектор-аналитик, аналитик-тестировщик и архитектор-программист).

                                                                  Затраты на проект выросли на 60% (роль архитектора и аналитика отнюдь не бесплатные).

                                                                  К чему я это всё: я не против ТДД, но надо знать, где его применять. В проектах с низкой мутацией требовании элементы TDD работают и работают неплохо (если не увлекаться слишком сильной детализацией архитектуры), но в проектах с высокой скоростью изменения требований TDD просто неэффективен.

                                                                  Сам я требую покрывать программистам только публичные интерфейсы модулей системы и писать автоматизированные интеграционные тесты. Разрабатывать весь код по TDD считаю слишком большим оверхедом.
                                                                  • –2
                                                                    И, да, я видел несколько проектов в крупных компаниях, где TDD был эффективен. Впрочем, после этих компаний у меня сложилось впечатление, что чистый TDD может применяться только вместе с RUP или Waterfall.
                                                                    • +12
                                                                      Константин, а как «непонятно, как писать функциональные требования» связано с написанием юнит-тестов? Речь идёт именно про юнит-тесты, не о функциональном, ни о приёмочном, где нужны юзер-стори. Юнит-тестинг напрямую не зависит ни от требований заказчика, ни от подробности ТЗ. Если программист пишет какой-то модуль либо дополняет его либо изменяет методы какого-то класса — просто пишутся/меняются соответствующие юнит-тесты, и архитектор тут совершенно ни при чём. «баги на спецификацию» — опять же, причём тут юнит-тесты? В основе, они тестируют модульные составляющие, на то они и «юнит». Ну а если меняется что-то внутри «модулей» системы, то тогда и тесты меняются соответственно, а иначе зачем они. Аналитики, архитекторы и др. доп роли и их отсутствие никак не должно влиять на наличие юнит-тестов программистов, потому что код пишется ими же и юнит-тесты ими же тоже. За общее функционирование системы отвечают функциональные/приёмочные тесты — они да, зависят от спецификации и юзер-стори заказчика.
                                                                      • +1
                                                                        Николай, объясни тогда, пожалуйста, каким откуда у программиста берётся время на написание юнит тестов? Мне кажется, что просто часть своего рабочего времени он эти юнит тесты пишет.

                                                                        А теперь, ответив на этот вопрос, давай подумаем: вот есть программист. Без юнит тестов он тратит на разработку N своего времени. Если он начинает писать юнит тесты, то времени он потратит N*k, k при этом явно существенно больше единицы. Таким образом для юнит тестирования мы должны гораздо больше дорогостоящего времени программиста.

                                                                        Если посадить рядышком архитектора, уточняющего функциональные требования, то k уменьшится. А можно и вообще свести k к единице, переложив функцию написания юнит тестов на куда как менее дорогостоящего джуниора. Архитектор и джуниор становятся экономически оправданными при з.п. в 1.5 и 1/3 по отношению к з.п. программера. Если не нанимать архитектора и джуниора программер по ТДД уже обходится существенно дороже.

                                                                        Следующий вопрос: нет ли выигрыша при использовании ТДД по времени разработки за счёт времени на тестирование? Ответ НЕТ! Не выигрывает. Опыт меня и моих коллег показывает, что как надо было тратить 50-70% времени на неавтоматизируемые регрессы, так и с внедрением континиоусинтегрейшн продолжаем тратить столько же времени. Вопрос — почему? Ответ — гетерогенная среда и высокая мутабельность требований к программе.

                                                                        Преимущество ТДД не в скорости или тоимости разработки, а в лучшем контроле качества кода в итоге, но не более того. ТДД — это не Святой Грааль и внедрять его там, где он не нужен — это проигрывать гонку с затратами на разработку.
                                                                        • +1
                                                                          Постараюсь в порядке очереди вопросов.

                                                                          Для конкретизации, предположим, что существуют условия, при которых программист (предпочитаю понятие «разработчик»), имеет область задач, где определённые не запрещённые требования могут выполняться. Например, идеальная схема Заказчик --> PM --> Tech Lead --> engineer. При других выдуманных схемах, не входящих ни в одну из утвержденных методологий, смысла говорить о «правилах» разработки, считаю, нет.

                                                                          а) Откуда время у программиста.
                                                                          По известным agile-методологиям существуют специальные мероприятия (например, планирование итерации), на которых непосредственные разработчики оценивают трудозатраты предстоящих задач (например, в очках или часах). Если заказчик/PM/кто-то-другой в прямой форме даёт понять, что «время ограничено только непосредственной разработкой кода» — вопрос не имеет места. Но оценка задач при выбранной методологии должна включать наличие написания тестов, если таковые имеются.

                                                                          b) Безусловно, программист (разработчик) тратит больше времени на код и тесты для кода, чем на просто-код, к гадалке не ходи. «Дорогостоящее» время разработчика — его цена коррелирует с базовым ТЗ заказчика. Например, заказчик явно указал: «Я не готов платить за дополнительный % времени на написание тестов. Пожалуйста, пишите код без тестов — приоритет на общем состоянии проекта без учёта 100% безошибочной функциональности, пусть бажно, если есть баги. Опять же, тут вопрос посвещённости заказчика в суть проблемы и принятия им решения на основе последствий — не проблема программиста при наличие PM.

                                                                          c) Архитектор, безусловно, может уменьшить функциональные требования, ибо функциональность заложена в самом понятии „функциональности“. Но ни один архитектор в здравом уме не будет писать юнит-тесты ни за одного программиста — иначе это не архитектор. Перекладывать функцию юнит-тестов на джуниоров… честно говоря, я не знаком ни с одним agile-подходом, который бы освобождал разработчиков от написания тестов и перекладывания на джуниоров.

                                                                          d) Не нужно путать разработчика (junior || seniour) с тестировщиком. Одно дело — юнит-тесты на код, представляющий собой чёрный ящик, другое дело — функциональное/приёмочное тестирование на основе юзер-стора заказчика, существующее независимо от кода. Если оно не нужно заказчику — опять же, ответ не имеет смысла.

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

                                                                          ЗЫ:

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

                                                                          Юнит-тесты — не определяют методологию TDD: TDD включает в себя не только понятия, по и последовательность действий и лояльное осознанное отношение к самому процессу.

                                                                          Про мутабельность и пр. — это, имхо, отдельная тема. Основной вопрос — выбрать TDD в ущерб чему-то или нет. И другой вопрос — тратить время хотя бы на unit-tests или нет.
                                                                          • 0
                                                                            «И другой вопрос — тратить время хотя бы на unit-tests или нет.»
                                                                            Коль, моя позиция проста: тратить время на юнит тесты необходимо, но не везде. Юнит тестами надо покрывать внешние интерфейсы атомарных модулей. Критерий атомарности модуля —
                                                                            а. код, который может по требованиям написать средний программист компании с 0 за неделю
                                                                            б. критически важный для системы сегмент, вынесенный по этим причинам в отдельный компонент
                                                                      • +3
                                                                        theOnlyBoy расписал все в точности, что я хотел сказать
                                                                        С чего вы взяли, что при использовании TDD вам нужен в довесок архитектор + тестер + бизнес аналитик?
                                                                        Так же ваше заявление, что на проектах, где меняются бизнес требования часто, TDD неприемлим, из моего опыта, это абсолютная неправда. Если проект следует TDD, все и вся покрыто тестами, то когда приходит новый реквест поменять функционал, меняется тест, меняется код + все это ранится и у разработчика, который сделал изменения есть уже 99% уверенность, что все работает. В убер трупер проектах, без тестов, разработчик как на минном поле, он должен сто раз перепроверить эффект своего изменения, потратить как вы сказали 30% на код и 70% на верификацию, и еще потом находится в сомнениях. При TDD разработчик тратит 50% на код, 50% на тесты (это если с нуля), если надо поменять код, то 80% на код и 20% на тест.
                                                                      • 0
                                                                        Вы лукавите как минимум.
                                                                        Получается, что при первом подходе программист начинает кодировать на основании НЕПОНЯТНЫХ ЕМУ требований?..
                                                                        • 0
                                                                          Да, именно так. Хороший программист вполне способен сам уточнить требования у продакт-менеджера, для этого продакт и нужен, чтобы быть медиатором между бизнес задачами и задачами разрабоки.
                                                                          • 0
                                                                            Ну так и при написании юнит-тестов пусть он делает то же самое без всех этих введений архитекторов и аналитиков.
                                                                          • 0
                                                                            Сколько процентов времени он тратит непосредственно на кодинг, а сколько на уточнение задач?
                                                                            • 0
                                                                              Сильно зависит от скорости мутации требований. Обычно на обсуждение функционала выделяется по 1-1,5 часа два раза в неделю при эффективном рабочем времени в 30 рабочих часов в неделю.
                                                                              • 0
                                                                                а сколько времени выделяется на проверку результата, кто и как этим занимается?
                                                                                • 0
                                                                                  Функционал проверяется тестировщиком, который вначале с продактом пишет/уточняет тест-план, а потом составляет список регресс-тестов.

                                                                                  Время на прохождение тестов и правку багов обычно соотносится как 2 к 1 по отношению к времени разработки. Увеличение до 7 к 3 является поводом для тотального код-ревью.
                                                                        • +2
                                                                          Что-то не вижу связи между архитектором и TDD, в любом случае даже средний разработчик без TDD и архитектора будет декомпозировать задачу на модули, а покрыть их хотя бы базовыми тестами после освоения самой технологии тестирования не займёт много времени, а дальше уже тесты будут пополняться в процессе.
                                                                          А выигрыш от минимизации отладки скорее всего покроет потери от написания тестов.
                                                                          Изменения требования конечно создают проблему, но без тестов проблем будет больше — служба поддержи нужна будет больше
                                                                          • 0
                                                                            Прочитайте пожалуйста: habrahabr.ru/blogs/tdd/112685/#comment_3611572
                                                                            • 0
                                                                              Начал читать «Совершенный код» Макконнелла, так вот он пишет что масса исследований подтверждает что чем раньше найдена ошибка тем дешевле её исправить и цена возрастает на порядок, т.е. увеличени стоимости разработки должно компенсироваться уменьшением стоимость правки багов.
                                                                              Имею свежий пример когда нашёл не совсем очевидный баг просто собравшись писать тест, код только написал, он весь в памяти, поэтому только подумав о тесте, я понял где может быть проблема, уверен что маловероятно обнаружения этого бага при тестировании, а если бы возник на продакшене, пришлось бы всё дебажить — код бы подзабылся.
                                                                              Ну и отладка при наличии тестов должна быть короче.

                                                                              Касательно, откуда время я ответил изначально, это выбор разработчика, в одинаковых условиях один находит время, и при этом никак не страдает, а считается экспертом
                                                                              • 0
                                                                                я имею ввиду комент habrahabr.ru/blogs/tdd/112685/#comment_3611544
                                                                                • 0
                                                                                  Это, конечно, да. Я и не отрицаю необходимости написания юнит-тестов. Но не всегда. Есть ситуации, когда это просто экономически невыгодно.
                                                                          • +4
                                                                            Слышал часто: "… потому что нет времени на это" и «а нафига, у нас есть тестеры, которые проверяют».
                                                                            • 0
                                                                              Очень хорошо, что появилась такая заметка. В комментариях к последней статье меня, возможно, обоснованно, критиковали за то, что я очень мало внимания уделяю автоматизированному тестированию.
                                                                              Наверное так и есть: когда пишу код, то задумываю схему тестирования не так уж часто, и это при том, что тестирование встроено в «родной» фреймворк.
                                                                              В чём моя отговорка? В том, что мне чаще всего трудно формализовать те требования к коду, которые я не мог бы отладить в голове. Грубо говоря, трудно формализовать требования к работе сцеплений, если это не какая-то явная ошибка, а совпадение событий, о котором поначалу даже и не думаешь.

                                                                              Например, есть класс, который как-то работает с ГУИ, взаимодействует с массой других объектов, внутренних и внешних, часть из которых обрабатывает данные в отдельных потоках. Проблема «перемалывания» известных входных данных этим классом, чаще всего, для меня не стоит (потому что класс либо простой, либо для него был создан и протестирован небольшой этюд). Реальные проблемы проявляются в runtime: внутренние объекты возвращают специфические состояния, каждое из которых не является ошибочным, но вместе это так влияет на сообщения класса внешним объектам, что иногда может произойти та или иная логическая ошибка. То есть цепочка «если ...» настолько велика и заранее непредсказуема, что я не представляю как заранее создать такую ситуацию. Как правило, о таких ошибках сцепки классов поначалу даже не задумываешься.
                                                                              • 0
                                                                                Что такое «для него был создан и протестирован небольшой этюд»? По описанию это очень похоже на юнит-тест. Может, вы как раз и пишите юнит-тесты, просто по-другому их называете?..
                                                                              • +5
                                                                                Два примера проблем с юнит-тестами:

                                                                                — Разработка ПО для синтеза звука. Типичный результат багов — дефекты звучания, призвуки. Для тестирования нужны уши и мозг, создание AI для тестирования проблематично.

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

                                                                                При этом в обоих случаях есть и автотестируемые регрессии, но за весь цикл разработки проекта они портят всего несколько человеко-дней, в то время как не-автотестируемые — причиняют очень неслабый объём работы.
                                                                                • 0
                                                                                  Будет и на их улице праздник.
                                                                                  • 0
                                                                                    Ну как бы известно же, что юнит-тесты — это самый низкий уровень, они и не должен тестировать звуки, цвет, ну и вообще поведение системы в целом. Они должны тестировать отдельные функции. Ну например, есть же у вас функция, которая подсчитывает ряд фурье, интеграл и т.п. — вот её и надо юнит-тестировать.
                                                                                  • +1
                                                                                    Я не могу протестировать код, потому что я точно не знаю, как он должен работать
                                                                                    На это сложно реагировать без недоверия. Если вы точно не знаете, как должен работать код, как вы вообще могли начать его писать? Сперва нужно понять требования.


                                                                                    это имеется ввиду, чужой код
                                                                                    • +7
                                                                                      ИМХО пропущен самый главный пункт:
                                                                                      я не пишу тесты, по тому, что не знаю как это делать, в институте не научили, английский я не выучил, а на русском книг нет. «А в Delphi/VB это в меню где что нажать надо?»
                                                                                      • 0
                                                                                        Порадовался за свой универ — у нас на практике по ООП отрабатывали юнит-тестирование, на реализациях разных паттернов программирования. Было на самом деле удобно их реализовывать с помощью тестов. Там же узнал(и читал/читаю) из списка рекомендованной литературы про TDD(книга К.Бека) и про Б.Эккеля «Философия С++». И про паттерны.
                                                                                        Вчера разбирался как тесты к NetBeans 7.0b прикручиваются — вроде удобно. Собираюсь покрыть ими одну свою программку — посмотрим, что получится.
                                                                                      • +22
                                                                                        Несколько странная статья. Первый абзац – автор говорит про TDD, потом вводная «Все мы слышали множество оправданий, почему кто-то не использует TDD», но весь остальной текст по сути к TDD относится постольку-посколько. По сути, речь идет о поводах не писать юнит тесты (на что намекает заголовок), а вовсе не про использование/не использование TDD методологии.

                                                                                        Вообще, подобным совмещением TDD и юнит тестов, пропагандисты TDD добиваются обратного результата. Человек копнет глубже в TDD, поймет что это такое, вздрогнет и больше не подойдет к юнит тестам вообще. И ничего странного, ведь все «знатоки» прямо отождествляют эти два, совершенно разноуровневых понятия.
                                                                                        • 0
                                                                                          Я виню юношеский максимализм ;) «Если использовать юнит-тесты в принципе, то сразу в режиме ТДД».
                                                                                          • 0
                                                                                            Мне кажется, в контексте данной статьи разница между юнит-тестами и TDD совершенно не важна.
                                                                                            • 0
                                                                                              я не очень понимаю, какой в этой статье особенный контекст, который делает прямую и явную неграмотность автора текста настолько неважной. Может не неграмотность, но умышленное введения читателя в заблуждение, я не знаю. Да и контекст этот мне трудно определить. Это про что, вообще было? Про «Все мы слышали множество оправданий, почему кто-то не использует TDD» или все таки про «Я не пишу юнит тесты… »? Подобная мешанина встречается на каждом шагу и вносит в нестойкие головы тех, кто тесты еще не пишет твердое, но очень ошибочное определение — юнит тесты это TDD
                                                                                          • +6
                                                                                            Качество кода нужно повышать ровно до той отметки, пока затраты на улучшение качества ниже, чем потенциальное увеличение прибыли от повышения качества.

                                                                                            Это должен понимать каждый программист, чтобы не заниматься перфекционизмом в ущерб коммерческим интересам проекта.
                                                                                            • +12
                                                                                              КО напоминает:
                                                                                              тесты != unit-тесты
                                                                                              TDD != unit-тесты

                                                                                              • +3
                                                                                                Я знаю, что такое юнит-тесты, я знаю, какую пользу они приносят. Но я не пишу юнит-тесты, потому что хотелки заказчика появляются как грибы после дождя — в случайных местах и не всегда понятно, какой именно гриб перед тобой. Несмотря на всю формальность процесса (SRS, CR, итерации и т.д.) получается примерно следующее:

                                                                                                хотим, чтобы шрифт здесь был 10 — описано в SRS — сделано — а нет, у нас названия сюда не влезают, хотим 11 — заведен CR — сделано — прошел месяц — не, ваще не хотим здесь ничего, пусть это появляется там и настраивается через визард — заведен CR, но что именно нужно настраивать через визард еще не знаем, нет спеки — делаем что-то — оно им (не)нравится, и так несколько раз — нашли, что нужно — под уже готовый(!) функционал делается запись в SRS. На последних этапах этого «процесса» уже даже CRы не заводятся, зачем, все равно всем понятно, что никому ничего не понятно.

                                                                                                Это уже смело можно назвать BDD — Bug Driven Development =) Заказчик выдвигает абстрактные требования без какой-либо конкретики — разработчик делает что-то, процесс повторяется через заведение багов в JIRA.

                                                                                                В этом процессе на поддержку уже существующих юнит-тестов уходит 80% времени. Просто чтобы они удовлетворяли актуальному видению заказчика. Все это приводит к весьма плачевным результатам — старые тесты тупо удаляются, а новые не пишутся. В последствии что-то менять — смерти подобно.
                                                                                                • +2
                                                                                                  А за что собственно минусуете? Вполне себе нормальная ситуация. Только если в статье всё плохо, потому что программист какой-то неправильный, то ситуация с правильным программистом и неадекватным менеджером существует и достаточно распостранена.
                                                                                                  • 0
                                                                                                    По-моему, тест, который тестирует размер шрифта — это немного странный тест. Как тут уже было сказано, тестировать надо бизнес-логику, т.е. вход-выход отдельных функций. При чём тут шрифты?..
                                                                                                  • +1
                                                                                                    По-моему это обычное дело, когда заказчик выдвигает абстрактные требования. У него есть какая-то проблема, он не знает как её решить (скажем, потому что не обладает нужными компетенциями), но очень хочет и для этого обращается к разработчику.

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

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

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

                                                                                                    Может быть он вам не доверяет? В этом случае постарайтесь доказать свою компетенцию, чтобы у него не было сомнений. А может быть вы сами снимаете с себя ответственность за выработку решений? Тогда естественно эту функцию он будет брать на себя и станет выдумывать решение сам (ведь больше не кому).
                                                                                                    • 0
                                                                                                      Задача разработчика как раз и состоит в том, чтобы выявить «паталогию», придумать решение и реализовать.

                                                                                                      Первые два пункта мне казалось, что задача аналитика
                                                                                                      • 0
                                                                                                        «хоть горшком назови». кто работает с требованиям заказчика, тот и должен этим заниматься. :)
                                                                                                  • +2
                                                                                                    Из личного опыта могу сказать точно, что при работе на больших и долгосрочных проектах Unit-тестирование — это лучший способ тестирования, при этом необходимость традиционных способов тестирования не отпадает. Отсюда следует, что отговорка «Нет времени» — это самая дешевая отговорка, т.к. на начальном этапе Unit-тестирование действительно требует чуть больше времени, но уже через 3-4 месяца, когда проект становится больше и сложнее, все время потраченное на тестирование полностью компенсируется на ускорении внедрения нового функционала и отлова багов в уже существующем.

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

                                                                                                    И самое главное чтобы не получилась ситуация: «Научи дурака молиться он лоб расшибет», важно понять, что нет необходимости тестировать 100% (этого и не получится). Тестировать надо бизенс-логику.
                                                                                                    • 0
                                                                                                      но уже через 3-4 месяца

                                                                                                      оправдано ли применение TDD в случае 2-3 недельных проектов, которые гарантированно не будут поддерживаться разработчиком в будущем?
                                                                                                      • 0
                                                                                                        Если Вы разрабатываете этот проект на базе каких-то инструментов то скорее всего эти инструменты уже будут покрыты тестами, все остальное уже Ваше личное дело, если Вы хотите гарантировано закрыть проект без косяков, тогда тесты будут нужны, т.к. в случае возникновения проблем на проекте заказчик скорее всего обратиться к Вам. Если же проект ну совсем простой и точно не будет дальше дорабатываться тогда думаю, что ничего страшного если тестов не будет.
                                                                                                    • 0
                                                                                                      Новый проект начинаю с тестов, но быстро забиваю на них, так как тесты разрастаются куда быстрее кода. Простой пример, функция с телом return new SomeClass() — нужно проверить, что что-то вообще возвращается, что возвращается объект, что этот объект инстанс SomeClass, что он правильно проинициализирован. Потом появляется необходимость ввести параметр в функцию, который тупо передаётся в конструктор, где тупо присваивается публичному свойству — приходится сначала изменять уже написанные тесты, а затем писать новые тесты на то, что хоть что-то сохраняется, что тип не изменился, что сохраняется то, что передаётся. Ладно, с этим справились, начинается самое интересное — используемый фреймворк поддерживает только паттерн ActiveRecord и объекты модели наследуется от базового класса, который инкапсулирует БД. На две строчки obj = SomeFactory::getNewInstance(className, params); obj.save() приходится писать ещё штук 20 тестов, проверяющих не только что объект пишется и читается то, что записалось, но и что корректно выкидываются любые эксепшены, которые могут возникнуть при работе с БД, начиная от невозможности подключения заканчивая нарушением целостности, и как раз на этом месте энтузиазм, как правило, иссякает.
                                                                                                      • +1
                                                                                                        Нет необходимости тестировать каждый класс-наследник ActiveRecord — достаточно протестировать сам ActiveRecord (save, delete, update, find и др. базовые вещи) на базе тестового Mock-объекта, и тем более каждый раз проверять а корректно ли произошло подключение к БД.
                                                                                                        Библиотека работы с БД (если такая есть во фреймворке), также должна тестироваться один раз, в одном месте, в противном случае Вы тестируете уже протестированное, а это избыточность тестов, которая собственно Вам и портит настроение писать тесты.
                                                                                                        • 0
                                                                                                          Ну тестирую я не сам ActiveRecord (тесты для него есть в фреймворке), а связь своего класса с таблицей в БД (что маппинг правильно настроен другими словами), что ограничения введенные в схему БД (уникальные индексы, внешние ключи, ограничения на размер данных и т. п.) правильно работают, что переопределенный save() хотя бы вызывает родительский save(), а не попал в «мёртвый код» и т. п. Про подключение я, каюсь, добавил для красного словца, но как-то так получается, что одна строчка кода вызывает необходимость писать чуть ли не десятки тестов. С DataMapper было бы, наверное, проще тестировать модель, но, увы, скаффолдинг в фреймворке работает только с ActiveRecord.
                                                                                                          • +1
                                                                                                            Есть опыт запуска двух больших Интернет-проектов на фреймворке также поддерживающем только ActiveRecord, сначала тоже тестировали все модели, свойства и методы, но потом, когда тесты начали превращаться чуть-ли не copypaste, т.к. все модели в основном однотипны, успешно забили на это дело и переключились исключительно на тестирование бизнес-логики, вот тогда дело и пошло веселее.
                                                                                                            Я конечно не знаю Вашей ситуации, но есть подозрение, что частично такая модель применима, ну если нет, так нет.
                                                                                                            • 0
                                                                                                              Грубо говоря, инициализируете объекты модели, вызываете какой-то метод, проверяете или его возврат, или изменение состояние объекта и на этом успокаиваетесь?
                                                                                                              • 0
                                                                                                                по-хорошему да, например возьмем тот же ActiveRecord на примере функции save

                                                                                                                • 0
                                                                                                                  методоы getAnyproperty и setAnyProperty — явно не объявлены и обыгрываются при помощи magic-метода __call PHP.

                                                                                                                  Таким образом, нам достаточно проверить только один объект, а все остальные модели смысла нет, т.к. абсолютное большинство, я думаю, будет однотипным.
                                                                                                                  • 0
                                                                                                                    class ActiveRecord {
                                                                                                                    public function save() {//do something}
                                                                                                                    }

                                                                                                                    class SomeClass extends ActiveRecord {....}

                                                                                                                    $obj = new SomeClass();
                                                                                                                    $obj->setSomeModelProperty(«value»);
                                                                                                                    $obj->save();

                                                                                                                    // Проверка сохранения, если ID есть, то сохранило
                                                                                                                    $this->assertTrue(!is_null($obj->getId()));

                                                                                                                    // Проверка установки значение через __call
                                                                                                                    $this->assertTrue($obj->getSomeProperty() == «value»);

                                                                                                        • 0
                                                                                                          Если сложно написать тест то с кодом что-то явно не так.
                                                                                                          • –1
                                                                                                            Даже если отвлечься от фреймворка, модели которого сильно связаны с классами ORM, то рассуждаю примерно так: нужен метод, возвращающий объект класса MyClass с одним свойством и конструктором с параметром — значением этого свойства. Начинаем TDD:
                                                                                                            — пишем тест, что Fabric::getInstanceOfMyClass(5) возвращает не null
                                                                                                            — запускаем — ошибка, метод не существует
                                                                                                            — пишем метод function getInstanceOfMyClass() {}
                                                                                                            — запускаем — ошибка, метод без параметров, а передано одно целое
                                                                                                            — добавляем параметр в метод function getInstanceOfMyClass(param) {}
                                                                                                            — запускаем — ок
                                                                                                            — пишем тест, что метод возвращает вообще хоть что-то (не NULL)
                                                                                                            — запускаем — ошибка
                                                                                                            — добавляем return 1
                                                                                                            — запускаем — ок
                                                                                                            — пишем тест, что возвращается объект
                                                                                                            — запускаем — ошибка
                                                                                                            — исправляем return new SomeClass() — ок
                                                                                                            — пишем тест, что метод возвращает MyClass
                                                                                                            — запускаем — ошибка — класс не определен
                                                                                                            — пишем класс class MyClass() {}, настраиваем его загрузку
                                                                                                            — запускаем — ок
                                                                                                            — пишем тест, что свойство prop проинициализировано (не NULL)
                                                                                                            — запускаем — ошибка, свойства нет
                                                                                                            — дописываем в класс public prop;
                                                                                                            — запускаем — ошибка, NULL
                                                                                                            — пишем конструктор function constructor__() { $this->prop = "" }
                                                                                                            — запускаем — ok
                                                                                                            — пишем тест, что свойство целое
                                                                                                            — запускаем — ошибка
                                                                                                            — изменяем конструктор $this->prop = 0
                                                                                                            — запускаем — ok
                                                                                                            — пишем тест, что свойство равно 5
                                                                                                            — запускаем — ошибка
                                                                                                            — переписываем конструктор function constructor__(val) { $this->prop = val }
                                                                                                            — запускаем — ошибка, не передан параметр в конструктор
                                                                                                            — исправляем return new MyClass() на return new MyClass(1)

                                                                                                            Устал :) В общем ещё с десяток итераций и получим код
                                                                                                            ...
                                                                                                            class MyClass {
                                                                                                              public prop;
                                                                                                            
                                                                                                              function __construct($val) {
                                                                                                                $this->prop = $val
                                                                                                              }
                                                                                                            }
                                                                                                            ...
                                                                                                              function getInstanceOfMyClass($param) {
                                                                                                                return new MyClass($param)
                                                                                                              }
                                                                                                            ...
                                                                                                            


                                                                                                            покрытый десятком тестов на каждый чих

                                                                                                            По-моему перебор
                                                                                                            • –1
                                                                                                              нет
                                                                                                              • 0
                                                                                                                А что с кодом не так?
                                                                                                                • 0
                                                                                                                  С кодом всё в порядке.
                                                                                                                  Плюс у вас есть тесты, которые подтверждают, что с этим кодом всё в порядке.
                                                                                                                  • 0
                                                                                                                    Но тесты писать сложно для такого простого кода :(
                                                                                                                    • 0
                                                                                                                      нет
                                                                                                                      • +1
                                                                                                                        Мне сложно, правда понял почему из коммента ниже — слишком мелкие итерации делаю.
                                                                                                                        • 0
                                                                                                                          Вот видишь, даже плохой опыт написания тестов полезен, так как он влияет на «мировоззрение».