Количество unitTest’ов

Люди, а как вы выбираете количество unittest’ов, которое писать?

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

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

Собственно говоря, как вы выбираете, когда остановиться?

53 комментария to “Количество unitTest’ов”

  1. Serhiy Yevtushenko:

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

    На что не стоит писать юнит тесты — на ГУИ код (очень затратно по соотношению стоимость/выигрыш).

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

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

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

    • Victor Ronin:

      в целом идею понял. хотя все параметры достаточно не формальные.

    • Сложность юнит тестов на большие функции скорее говорит, что функция уже спроектирована неправильно, т.к. функцию становится возможно использовать уже только в 1 одном конкретном случае, где она собственно уже и используется.

      По поводу тестов на унаследованый код: есть великолепная книга Майкла Физерса о том юнитТестах и унаследованом коде, в частности в ней хорошо описаны разные стратегии, как навешивать юниттесты на уже существующую систему, в которой юнит тестов не было, в зависимости от того сколько ресурсов у тебя есть. Физерс в ней доходит до крайности и объявляет legacy code любой код, который не покрыт тестами.

      • Victor Ronin:

        Со всем согласен, книгу может гляну.

        В основном я интересовался о том, когда unitTest’ов достаточно по вашему мнению. Когда уже больше писать не надо.

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

          под «не проскакивают» имею в виду некий трешхолд.

  2. Anatoly Popov:

    Я не пишу юнит-тесты вообще.

    Кроме как к основополагающим вещам, которые возможно протестировать: контейнеры, какие-либо самопальные реализации известных алгоритмов и т.д.

    К сожалению, в остальных случаях тестер дешевле.

    • Serhiy Yevtushenko:

      А в связи с какой задачей возник вопрос? Спецификация уровня юнит тестов для аутсоурс проекта?

      • Serhiy Yevtushenko:

        Сорри, перепутал автора ответа

      • Victor Ronin:

        Да, собственно небольшой кусочек покрывая unitTest’ами и обнаружил, что я могу написать 20 штук, которые покроют 80% кода или 100 штук которые покроют 99% кода. Естественно 100 штук писать дольше. И вот я чешу в голове и думаю, а где останавливаются люди?

        • Anatoly Popov:

          На 20 + крайние случаи.

        • :))
          Не поверите, но вот проценты покрытия юнит тестами сильно зависят от человека и проекта. Встречал в английских книгах кого-то из апологетов ТДД, что покрытие должно быть 60-70%, буквально в следующей стоит уже число для покрытия — 100%.
          Степень покрытия каждый для себя определяет сам. Скажем по той же ссылке на James Shore’s «Let’s Play» — у него покрытие отнюдь не 100%, да и крайние случаи параметров он пропускает — и вместе с тем его код довольно рабочий.
          Для себя я решил следующим образом — тесты должны покрывать основную логику и взаимодействие с сторонними системами, крайние случаи только если на них найдены баги. А какое процентное значение — это дело десятое. Главное что я смогу отловить поломки при изменениях и использовать тесты как доп. проектную документацию, которая показывает как надо работать с создаными объектами.

    • Victor Ronin:

      Насчет тестеров дешевле — вопрос сложный. Ему каждый раз нужно платить за тестирование, а unitTest’ам один раз.

      • Anatoly Popov:

        Про то, что юниттестам один раз — это и есть самый главный миф.

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

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

          И таки да! юниттесты надо поддерживать, а то их просто прекратят запускать, исключат из билда, а в результате заказчик получит showstopper — спасибо уже проходили, больше не хочу.

          • Anatoly Popov:

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

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

            • Вариант с ТДД пропускаем — потому что это тупо гробит Ваш коммент.

              Юниттесты — это документирование ТЕКУЩЕГО решения, что к спецификациям задач проекта, которые документируют ЖЕЛАЕМЫЙ КОНЕЧНЫЙ результат, имеет довольно слабое отношение, если исполнитель, конечно, не junior developer, тогда — да. Тогда специально для него постановка задачи будет специфицирована очень строго и юниттесты конкретно для него не будут нести практический смысл.

              По поводу морлоков — тут мы упираемся в старую добрую экономику:
              если нет юниттестов, то «морлоки» вынуждены проходить всю систему полностью при каждой модификации или билде — иначе нет гарантии, что изменения не поломали какой-то элемент(у «морлоков» есть спецификация как всё должно работать, но нет знаний что Вы изменили):
              $ на действия после модификации = (время «морлоков» на тестирование ВСЕЙ системы)*(цену времени)*(количество билдов, которые надо проверять)
              Если есть юниттест, то количество его запусков на цену не влияет, тогда:
              $ на действия после модификации = (время апдейтнуть юниттест)*(цену времени)
              В большинстве случаев 2-я цена сильно меньше 1-й. Стоит добавить, что тестирование по спекам — это тестирование всей системы, а юниттесты — это тестирование компонентов — так что надо учитывать, что время на полное тестирование всей системы ВСЕГДА больше суммарного времени выполнения небольших «юнит» тестов по отдельности(комбинаторика, ёж вашу…). Также надо учитывать тот фактор, что не все те условия в которых будет жить система, «морлоки» могут воспроизвести сейчас в своих средах, и протестировать их можно ТОЛЬКО с помощью юниттестов.

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

              BTW
              Откуда вообще такой снобизм? «Морлоки» — как детский сад прямо… А то что тестирование по принципам белого и чёрного ящика это разные вещи, то мы забыли. А о составлении плана тестирования вообще никогда не думали… А о том что кроме юнит тестирования к дев тестированию ещё относят регрессионное и интергационное, так вообще даже не слышали…

              • Victor Ronin:

                Мои 2cent’а. Ключевым параметром является размер системы, длительность ее жизни и частота изменений.

                30Kb кода с длительностью жизни в 3 месяца и без изменений (один раз написана и выкинута) в unitTest’ах не нуждаются.

                10Mb кода с длительностью жизни в 10 лет и с достаточно активными изменениями, просто просит unitTest’ов.

                Некоторое количество параметров (а-ля, что делает система, насколько много кода связанно с UI) я оставил за рамками.

                • Anatoly Popov:

                  Просит то оно просит. Только по-хорошему, это ещё 10 Мб кода, которые надо написать и сопровождать. Что, в условиях константной производительности труда, требует увеличения штата разработчиков вдвое.

              • Anatoly Popov:

                Вариант с TDD пробовали, не работает. Возможно у нас конечно руки не оттуда растут, но вот так.

                Мы не коммитим в репозиторий хаки, которые не дают желаемого конечного результата. Это запрещено политикой компании.

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

                А насчёт не всё смогут воспроизвести — виртуализация спасает мир. У нас у тестеров в сумме парк физических и виртуальных машин шире и интереснее, чем у девелоперов.

                Снобизма нет. Просто есть квалифицированная работа, есть неквалифицированная. Проверять работу ПО по написанным спекам — менее квалифицированная. Все эти виды тестирования известны, причём здесь «юниттесты», крайне непонятно.

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

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

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

                • Serhiy Yevtushenko:

                  А вы могли бы уточнить специфику предметной области/софта, который разрабатывается вашей компанией? Чтобы можно было четко понять, что делает юнит тестирование для вашей компании экономически невыгодным?

                  • Anatoly Popov:

                    У нас основной продукт — система управленческого учёта.

                    А делает написание тестов экономически невыгодным то, чтобы их поддерживать, нам надо бы нанять ещё хотя бы 5-10 неплохих программистов. Тестеры дешевле.

                    • Serhiy Yevtushenko:

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

                    • вы, похоже, сами себя убедили, что вам надо _ещё_ 5-10 програмеров.

                      с таким настроем юнит-тесты не пишутся, это да.

                      юнит тест не призван ловить ошибки бизнес-логики — для этого таки есть тестировщики или тулзы типа селениума или фитнеса.
                      он призван сократить количество итераций «code-compile-check-error-code» _САМОГО ПРОГРАММИСТА_.

                      программист, который не проверяет свой код — это уже не программист, а заяц из мультика «и так сойдёт».

          • Anatoly Popov:

            Хм. Коммент ушёл в каптчу?

  3. С GUI уже сказали.
    Писать тесты на использование стандартных алгоритмов и оболочки вокруг стандартных классов имеет мало смысла, т.к. код уже вылизан. Тут больше поможет хорошее обсуждение на планировании или при code review, потому что ошибку в таком типе кода можно сделать только 1 раз, когда выберешь не тот алогритм или не тот контейнер.
    Писать юниттесты надо на логически или архитектурно нагруженные части кода. Там где код не является стандартным и вылизаным годами практики.
    В обязательном порядке писать на стороннее API, если есть хоть малейший риск, что оно может изменится — иначе нельзя будет понять откуда выросли новые баги, если в этом участке кода ничего не изменялось.

    А по поводу того что их надо поддерживать — так это плата за возможность обнаружить ошибку на более раннем этапе. К сожалению ничего бесплатно не приходит.

  4. kmmbvnr:

    1) Если тест написать просто (вызов апи — проверка результата) — я его пишу. Такие тесты не сложно поддерживать.

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

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

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

    5) Что-то сломалось и обнаружилось не сразу — пишу тест

    6) Периодически смотрю на покрытие кода, если вижу сложный кусок который может поломаться, пишу тест.

    Моки/стабы использую только для случаев 5-6. Т.к. такие тесты сложнее поддерживать.

    P.S. В текущем проекте — покрытие 60%

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

    • Victor Ronin:

      Не согласен.
      В бизнес требованиях вообще мало написано о модулях/классах. Поэтому отконвертировать бизнес требования в unitTest’ы к модулям/классам впрямую как-то малореалистично.

      Плюс, как пример, пусть у нас есть класс
      CFile
      и у него есть интерфейс Read(buffer, numberofbytes)

      Будем ли писать unitTest’ы на buffer = NULL или для numberofbytes > 4Gb, или для buffer размером меньше, чем количество байт, которые мы пытаемся читать.
      Будем ли мы писать разные тесты, для чтения из начала файла (offset 0) или с середины файла (offset <> 0).
      Будем ли мы писать тесты, для случая. когда в файле меньше байт, чем мы хотим считать
      И т.п.

      Тестов «в лоб» тут один — проверить чтение. Но дополнительных тестов может быть эдак с десяток.

  6. Serhiy Yevtushenko:

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

  7. Anatoly Popov:

    Дерево кончилось, начнём новое, если Виктор не против.

    2COTOHA:
    > вы, похоже, сами себя убедили, что вам надо _ещё_ 5-10 програмеров.

    У нас папка src весит 86 мегабайт (я удалил все бинарники, *.obj и прочее). Предположим, мы захотим покрыть всё юниттестами. Сколько нам времени понадобится?

    При этом, продукт необходимо развивать и поддерживать. Т.е. объём работ впереди далеко не нулевой.

    > юнит тест не призван ловить ошибки бизнес-логики – для этого таки есть тестировщики или тулзы типа селениума или фитнеса. он призван сократить количество итераций “code-compile-check-error-code” _САМОГО ПРОГРАММИСТА_. программист, который не проверяет свой код – это уже не программист, а заяц из мультика “и так сойдёт”.

    И что они будут проверять, если мы бизнес-логику убрали? Проверку на null где-то пропустили или ещё что-то? Ну так с этим вполне pex (http://research.microsoft.com/en-us/projects/pex/) или аналоги справятся.

    2Serhiy Yevtushenko
    > А какой стек технологий? И какова максимальная стоимость ошибки в системе?

    Много всего. VB6, C++, .Net, T-Sql. Максимальная стоимость ошибки, ушедшей в релиз, равна возможным потерям от планирования бюджета клиента, основанного на неверных данных.

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

    Ничего не могу сказать. Мне юниттесты пригодились не более десятка раз. Когда писал реализации протоколов и коллекций.

    • 1. не надо предполагать, что надо «всё обложить». или надо было это делать с самого начала — тогда бы вы сейчас этот вопрос не задавали. теперь у вас по факту легаси система, где юнит-тесты надо писать ситуативно:
      — что фиксили, то и обкладывать.
      — что часто «сыпется», то и обкладывать.

      если где-то нет юнит-тестов, но при этом нет и проблем — не надо ничего обкладывать.

      2. проверять они будут интерфейсы. если у вас не ооп или хай-кохешн, то это не про вас.

    • Victor Ronin:

      Я думаю, надо начать сначала, почему тестирование отдельного класса/модуля хорошо.

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

      Из реальной жизни. Есть модуль A, который лежит где-то в глубине системы и через него часто проходит исполнение. Приходит баг от заказчика. что что-то упало, сначала customer support тратит три дня, чтобы собрать данные и пытаться повторить, потом тестировщики тратят три дня на повторение бага, так как support не смог толком повторить. Вроде нашли похожий баг, отдают разработчикам, они ковыряют систему и через еще 3 дня выдают пофикс, который тестировщики проверяют, так как заказчик важный для него делают hotfix. Итого, потрачено X долларов. Только вот, разработчики починив этот баг, внесли два новых в этот модуль A, тестировщики это не отловили, так как во первых модуль A глубоко и поэтому они о нем ничего не знаю и не могут подергать все его интерфейсы.

      Через 3 месяца, уже приходят 2 заказчика. И повторяется та же самая ситуация.

      Проблема состоит в том, что исправления бага ушедшего заказчику стоит дорого. Условно говоря, те же самые 50 тестов для этого модуля A, могли бы в 5 раз уменьшить вероятность того, что при изменениях внесут новые ошибки. Написать 50 простых тестов (а unit test’ы должны быть простые) зачастую дело несколько дней. Итого нам может (не всегда) но может быть дешевле иметь тесты для модуля, чем перетестировать всю систему целиком для всех возможных комбинаций.

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

      • Anatoly Popov:

        Аналогия замечательная. Проблемы аналогии опишу ниже.

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

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

        Чтобы написать 50 простых тестов можно потратить несколько дней или запустить pex, если тесты уровня проверок на NullReferenceException. Он их сгенерит сам. Зачем их писать?

        Интеграционные же тесты, нагрузочные тесты, они есть.

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

        • «в идеале нам надо написать N моков, где N – очень большое» — для тестирования 1-го класса? А у Вас архитектурой точно всё ок? а то как-то странно…

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

          • Anatoly Popov:

            Повторю вопрос: если тесты уровня проверки «а не вернули ли нам нулл, где нельзя его возвращать» и вы их пишете, то я их генерить буду, если понадобятся, pex’ом.

            > для тестирования 1-го класса? А у Вас архитектурой точно всё ок? а то как-то странно…

            Да, всё ок. Есть, например, TransactionStorer. Для тестирования метода ExecuteBatch надо: мок клиента, мок БД, как минимум. А есть клиент этого TransactionStorer, для него надо мок этого TransactionStorer, например. Иначе смысл в этих юнит-тестах? Продублировать интеграционные?

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

        • Victor Ronin:

          Понял. Пошел почитал. Оказалось, что я unitTest’ы скорее пользую ближе к интеграционным тестам, чем к unitTest’ам.

          Да, если руководиться методикой, что unitTest должен быть атомарен и вокруг тестируемого класса, должны быть mock классы, то действительно количество времени написания и поддержке больше.

          • Anatoly Popov:

            Ну, иначе это не unittest, cогласно их определению.

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

            Толку, правда, неособо много, имхо.

    • Ну весит у Вас папка чистых исходников 86МБ и что? Если хотите помериться — то у меня на текущем проекте папка исходников весит 900МБ, но я же не бегаю и не хвалюсь этим…

      «Сколько времени чтобы обложить» — так Вас никто не заставляет обкладывать все исходники сразу юниттестами. Делайте как если бы Вы ели слона — «по кусочкам».
      Объём задач ненулевой… — ок, время на дополнительное покрытие функции юниттестами ~+10% от времени реализации. Время съэкономленое — (длина цикла тестирования + время сборки крешдампа для Вас — время запуска юниттестов)*количество неудачных попыток фикса. Или Вы Бог и фиксите любой баг ВСЕГДА безошибочно? Опять же ситуацию с 2-я багами, которые нейтрализировали друг друга никто не отменял.

      • Anatoly Popov:

        Вы где-то хвастоство видите? Я всего лишь пояснил, что система далека от «интернет-магазин» по объёму исходников.

        > “Сколько времени чтобы обложить” – так Вас никто не заставляет обкладывать все исходники сразу юниттестами. Делайте как если бы Вы ели слона – “по кусочкам”.

        Где взять слона, чтобы решить текущие задачи и написать тесты? Клиентам сказать «подождите, нам тут про TDD рассказали?».

        > Время съэкономленое – (длина цикла тестирования + время сборки крешдампа для Вас – время запуска юниттестов)*количество неудачных попыток фикса.

        Т.е. на 0-1? Велика потеря. Сборка крешдампа — 5-10 секунд + пересылка по вебу. Будем экономить?

        > Объём задач ненулевой… – ок, время на дополнительное покрытие функции юниттестами ~+10% от времени реализации.

        Мой опыт говорит, что для нормального покрытия (> 95%) в нетривиальных случаях требуется до 50% времени, если уже есть моки.

        > Опять же ситуацию с 2-я багами, которые нейтрализировали друг друга никто не отменял.

        Я пока такой не видел 🙂

        • Serhiy Yevtushenko:

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

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

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

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

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

          • Serhiy Yevtushenko:

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

  8. Антон:

    Не буду встревать дискуссию, а просто добавлю горчицы.

    Кто бы что не говорил, а отказываться от автоматических тестов (не важно — юнит, селениум и прочее) ИМХО глупо.

    Теперь по списку в стиле вопрос-ответ.

    1. Тесты нужно писать, а это «лишняя» работа!

    Да, работа. Причём это прямая обязанность разработчика.

    2. Автоматические тестирование можно заменить тестером.

    Опять же, ИМХО, глупо. Автоматические (юнит-)тесты проверяют аппликацию на уровень ниже, чем просто вывод. Это раз.
    А два — прогнать автоматические тесты — это на много быстрее, чем садить перед каждым релизом тучу леммингов и не нужно их «ждать».
    Следовательно три — экономнее.
    Четыре — точнее. Когда тестер делает одни и те же тесты, то замечено, что он легко может допустить ошибку. Это естественно. Мы боролись против этого чеклистами. Местами помогало, а местами нет.

    Но! Автоматические тесты не могут заменить тестеров — их нужно комбинировать.

    3. Тесты нужно поддерживать!

    Да, нужно. Но в частых случаях, если это не касается ГУИ, это показатель неправильных тестов. А в случае изменения бизнес-логики — ну что поделаешь. Но согласитесь — это происходит крайне редко.

    4. Заказчик не хочет платить за написание тестов!

    Довольно таки распространнённо — сам сталкивался. Однако эта ситуация решается довольно таки легко после подписания контракта с заказчиком о «Негарантировании стабильности и отказа от автоматических тестов». Клиент осведомлён о возможных «неприятностях» и на чём он экономит.

    А теперь о порытии.

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

    Всё мечтаю занятся TDD, но руки не доходят (даже книжку купил). Сейчас вот занимаюсь приватным проектом. Для себя делаю обычно так:

    1. Ставлю проект, что бы хоть как-то стоял.
    2. Пишу грубые тесты.
    3. Рефакторизирую, дополняю/изменяю тесты.
    4. Оптимирую, шлифую.
    5. Потом взависимости от критичности дополнений либо пишу тесты, либо жду момента для регрессионных тестов.

    • Victor Ronin:

      Со всем согласен, хотя в результате спора оказалось, что у Анатолия вполне неплохая база автоматических тестов (просто они интеграционные, а не unittest’ы).

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

  9. Может будет полезным(сам ещё не полностью досмотрел, потому не скажу о качестве материала):
    http://www.infoq.com/presentations/TDD-of-Asynchronous-Systems
    Кроме освещения ТДД для асинхронных програм, как побочную идею товарищ предлагает писать интеграционные тесты тоже в стиле ТДД, а не только юнит тесты