Добрый день!
Бизнес любит измерять, менеджмент любит прозрачность, а сотрудники не любят всю эту бумажную работу, в особенности если от них хотят неизвестно что… Процессы автоматизации тестирования не исключение. Я приведу 5 рисков, которые чаще всего встречаются, которые стреляют, которые нельзя недооценивать, которые могут привести к провалу всего тестирования и проектов в целом. Также я приведу примеры метрик, добросовестное использование которых поможет успокоиться вам, вашему начальству, бизнесу.
Помимо этих рисков существуют глобальные: неверный выбор стратегии тестирования, отсутствие ООП в создании фрэймворка и тестов… Но они, в отличие от первых, приводят лишь к увеличению стоимости тестирования, а не к провалу тестирования как такового, как процесса, как идеологии, как инструмента обеспечения качества продукта, а в конечном счёте лояльности клиентов, которые приносят вам доходы. Если вы, как специалист, можете объяснить это руководству, добиться от разработчиков уважения (его надо заслужить :) ), убедить всех в правильности выбранных подходов и стратегий, вы на верном пути.

Риски:


1. Если будем организовывать автоматизацию тестирования там, где она не нужна, мы выкинем кучу денег
Это первый и главный риск любого процесса. Руководители, особенно в странах постсоветского пространства, редко отличаются гибкостью. Если в голове есть представление, что автоматизация тестирования есть благо, то его будут пихать всюду где нужно и не нужно. Совсем забывается, что реальный возврат инвестиций в автоматизации тестирования возникает в лучшем случае со второго релиза. Нужно научиться объяснять бизнесу, что не всякая автоматизация даст качественное покрытие и что это будут просто выброшенные мотивация, время и деньги.

2. Если мы напишем десятки тысяч тестов, которые буду гоняться на CI в облаках, то мы обманем себя в вопросах качества
Это чаще всего встречающийся анти-паттерн. На нём остановлюсь подробнее — об остальных паттернах и анти-паттернах можно почитать здесь — синяя секция будет наиболее интересна всем, кто пишут unit-тесты. Это давно сформулированные анти-паттерны, которые уже можно отнести к аксиомам.
Без шуток — если мы допускаем тяжеловесные тесты, тесты-лжецы и так далее, мы обрекаем себя на провал проекта. Не раз, принимая участие в аудировании процессов тестирования в различных компаниях, я сталкивался с этим явлением, отговаривал автоматизаторов и руководство от написания тестов ради тестов. Некоторые слушали — и выгребали много всего плохого до внедрений, некоторые не слушали — 3 проекта рухнули в один день, хотя тестов зелёных было порядка 8000 тысяч на каждый.

CI в облаках — да, люблю эту тему. Зачем гонять функциональные тесты на сервере непрерывной интеграции, если тесты все гоняются 10 минут? Зачем CI, если релизы выкатываются раз в месяц, а не раз в день?.. Как и любой специалист в автоматизации тестирования, я овладел навыками создания скриптов для запуска всего этого чуда на TeamCity, но факт в том, что ни разу, в какой бы команде я ни работал, не приходилось использовать CI иначе как для сборки и прогона unit-тестов. Все функциональные тесты должны гоняться до коммита, а не после него. Я в этом убеждён… При таком подходе есть проблемы при кросскомандной работе. Но и они решаемы грамотной организацией процесса.

3. Если мы будем использовать изолированные входные данные для тестов, то пропустим Critical баги в production
В предыдущей моей статье предлагали разделить unit-тесты и функциональные авто-тесты. Я бы всё-таки старался этого не делать, и считаю, что в большинстве случаев данные не должны быть изолированными. Если мы можем внести случайность во входное поведение для теста, её обязательно надо включить. Пользователи (взывающие стороны методов, если речь идёт о unit-тестировании) всегда в среднем производят действие с данными в определённом диапазоне. Можно сделать провайдера входных данных, который опирался бы на это распределение и приблизить тем самым всё к реальности.
Например, недавно столкнулся с «фичей», которая ярким образом проявлялась у нас. Система ложилась на колени, если в ответ на запрос об оплате от банка приходил номер карточки длиной больше 16 знаков. Да, конечно, это нереально в нашем мире 16тизначных карточек, но, простите, а когда станет реально… когда клиентам банков перевыпустят карточки, и они начнут постепенно уходить из постоянных клиентов сервиса к конкурентам, а бизнес будет терять деньги, не понимая даже, что не так.

Rem: для Java любителей, — понятно, что используя reflection, можно написать инициализатор любого объекта любого класса, так как в конечном счёте это всего лишь дерево примитивов. Мало кто знает, но уже давно всё реализовано в чудесной библиотеке podam. Вот пример использования:

PodamFactory factory = new PodamFactoryImpl(); // Использует дефолтную стратегию генерации случайных данных
MyClass myPojo = factory.manufacturePojo(MyClass.class);

Также можно аннотациями задавать диапазоны значений и создавать собственные стратегии генерации. В общем — всё, что душе угодно. Намного удобней, чем вызывать setter-ы по всему дереву и, используя, Random и RandomUtils заполнять объект данными. Использование Podam либы вместе с Mockito даёт поразительные результаты с точки зрения лаконичности инициализации возвращаемых заглушкой объектов.

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

5. Если разработчики не понимают, зачем нужна автоматизации тестирования, не сотрудничают в этих вопросах и воспринимают всё, как обязаловку, то автоматизация тестирования будет неэффективна
При аудите я всегда начинаю с беседы с разработчиками. Оказывается, что 3 из 5 разработчиков абсолютно уверены, что эти вот тестировщики (тут уж неважно мануальные или автоматизаторы) просто проедают зарплату. На вопрос «почему вы так считаете?», ответы всегда разные, но суть одна — «нам это не нужно, потому что мы итак прекрасны». Один разработчик из 5, считает, что автоматизация тестирования нужна, что он уже сто раз ставил эти вопросы в компании, но не находил поддержки у коллег. Ещё 1 всех давно уже послал и сам пишет тесты, потому что считает это необходимым, навязывать никому ничего не хочет. Так он обеспечивает качество своей работы. В такой обстановке нужно начинать с переделывания отношения у самоуверенных разработчиков к тестированию. Иначе можно даже не пробовать ставить процессы автоматизации тестирования, потому что тесты гоняться не будут, а даже если и будут, то на результаты никто не будет обращать внимания.

Метрики


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


Понеслась. Умножение на 100% буду опускать — не злитесь.

1. Процент автоматизируемых тестов.
Да… Увы, не всё нужно автоматизировать и не всё возможно автоматизировать. Если у вас есть список тестов, которые хотелось бы автоматизировать, то было бы логично измерить

PA(%) = количество тестов, которые могут быть автоматизированы / количество всего тестов.

2. Процент продвижения автоматизации

AP(%) = количество автоматизированных тестов / количество тестов, которые могут быть автоматизированы.

Эта метрика очень полезна при рассмотрении во времени процесса автоматизации. Если с каждым новым спринтом этот процент падает, стоит задумать о том, почему такое происходит — пересмотреть взгляды, архитектуру, добавить при необходимости людей в команду и т.д. Конечно, стремимся тут к 100%

3. Продвижение тестирования

TP = количество написанных тестов / промежуток во времени

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

4. Процент покрытия

TC(%)= количество написанных тестов / количество требований

Мутная, но полезная метрика, когда речь идёт об оценке глубины покрытия. Лучше даже, наверное, брать обратную пропорцию в качестве процента… Если грамотно её использовать, например, фича-тесты в Agile, то можно не только прикинуть сколько будет тестов через несколько месяцев, но и понять, что пришло время оптимизировать что-то, чтобы сократить время прогона этих самых тестов.

5. Плотность дефектов

TC(%)= количество открытых дефектов / общий размер продукта

Крайне важная метрика, которой пренебрегают ввиду отсутствия разумной возможности оценить, что такое размер продукта. Есть классическое представление о том, что в среднем на 3 строчки кода приходится по одному дефекту. По мне так это бред, а если это так, то, простите, тестирование уже не поможет :) В общем, для Scrum процесса можно в качестве этого самого размера продукта просуммировать story points, — если найденных дефектов мало, нормируйте формулу. В любом случае, это очень полезная метрика как внутри команды, так и снаружи, — особенно когда продукт готовится к выходу в свет. Вообще agile автоматизация тестирования — это отдельная песня. Желающие могут почитать про неё здесь

6. Эффективность устранения дефектов

DRE(%)= дефекты, найденные во время тестирования / (дефекты, найденные во время тестирования + дефекты, найденные пользователями в production)

Крайне важная метрика, без которой никуда. Если по результатам прогона автотестов мы имеем, допустим, 15 дефектов, исправляем их, а после выкатывания на пользователей мы замечаем ещё 15 новых и коварных, то печаль — значит не следили за метриками выше… Получив этот процент, надо как можно скорее поднять его в 100%. Так что эту метрику нужно рассматривать во времени после деплоймента. Тесты на вновь возникшие дефекты должны быть написаны немедленно и должны падать, а не проходить :)

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

6 февраля 2013 года я опубликовал статью в Journal of Mathematical Sciences (New York), 2013, 188:6, 758–760. Abstract и начало можно посмотреть здесь.
О чём там подробно рассказывать не буду, но как следствие одной из теорем, приведу пример, который так часто проявляется в провальных проектах — если каждый новый максимум количества открытых дефектов при условии, что прошлый максимум количества открытых дефектов = x, достигает значения порядка x^2, то проект оказывается в условиях равномерного распределения количества дефектов. То есть, увидев такую тенденцию, будьте готовы к тому, что перестанет работать весь функционал — причём очень быстро. Эта закономерность подтверждалась много раз на практике, да и не только с максимумами дефектов…

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

Комментарии (12)


  1. RPG18
    06.04.2015 10:51

    По второму пункту вопрос: как тесты влияют на показатели качества?


  1. FranciscoSuarez Автор
    06.04.2015 10:57
    +1

    Я, если честно, не понимаю Ваш вопрос. Сформулируйте, пожалуйста, точнее… Автоматические тесты — это инструмент для достижения какой-то цели — , например, понижения в среднесрочной перспективе стоимости регрессионного тестирования.


    1. RPG18
      06.04.2015 11:13

      Список показателей качества большой: понятность; полнота; краткость; портируемость; согласованность; сопровождаемость; тестируемость; удобство использования; надёжность; cтруктурированность; эффективность; безопасность. Не занимаемся ли мы изначально самообманом, считая что автоматезированное тестирование как-то повлияют на показатели качества?


      1. FranciscoSuarez Автор
        06.04.2015 11:25
        +1

        Ну так же можно считать самообманом, что IDE повышает скорость и качество разработки и что лучше всё писать в блокноте. Давайте отойдём от споров на тему глобальных определений и будем считать качеством соответствие продукта прямым требованиям и косвенным. Фактически автоматизация тестирования является инструментом для поддержания этой идеи.
        «Понятность: Назначение ПО должно быть понятным, из самой программы и документации.»
        Вы уж простите, но автоматические тесты для этого не предназначены.

        К тому же, в Вашей ссылке на Вики:
        «Фактор качества ПО — это нефункциональное требование к программе...»

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


        1. RPG18
          06.04.2015 23:12

          Тогда пожалуйста правильно используйте термины. Понятие качество в том виде в каком представлено в вики можно увидеть у Роберта Гласса в «software conflict 2.0 The art and science of software engineering» и у Стива Макконнелла в «Code Complete».

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


          1. FranciscoSuarez Автор
            07.04.2015 01:02

            Я стараюсь правильно использовать термины. По-прежнему не понимаю, что сказал не так. Если, говоря качество, имел ввиду ту часть качества, которая обеспечивается тестированием, а вам не нравится, что обеспечение качества — это не тестирование лишь, а совокупность мер… Ну ок… Это само собой и не противоречит тому, что написано в пункте 2. Если же я оскорбил чьи-то чувства… Ваши или Роберта Гласса или Стива Макконнелла, то прошу прощения. Не хотел… Просто привык говорить по существу, а не вязнуть в вопросах безукоризненной точности определений


  1. dougrinch
    06.04.2015 22:20

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

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

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

    В предыдущей моей статье предлагали разделить unit-тесты и функциональные авто-тесты. Я бы всё-таки старался этого не делать,

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


  1. FranciscoSuarez Автор
    06.04.2015 22:57

    Повторяемость — безусловно важная черта тестов. Безусловно, реализация рандомизации должна отличаться «от простой замены констант на рандом». Конечно, тут нужно и логирование красивое и понятное — это, безусловно искусство. Основная идея, которую я уже не раз реализовывал, — это взять распределение наиболее вероятных значений (провести исследования, например), создать стратегию генерации случайных входных данных с разбросом в пределах нескольких сигма от матожидания. В результате мы получаем максимальную эмуляцию пользователя, — тест начинает быть не given-then, а given(спектр)-then(спектр). Да, ожидаемый результат будет варьироваться. Если тест раньше набивал один конкретный товар в корзину интернет-магазина и проверял конкретную цифру, которую заранее сгенерил и залил в базу, то теперь он будет добавлять случайные товары, которые надо будет верифицировать в конце суммами, наименованиями и прочими разностями. Конечно, цены в диапазоне, количество товаров в корзине в среднем, например, 4 +-.

    Да, порой случается, что рандомизированные входные данные приводят к нестабильности теста при повторениях — это и есть тот прекрасный результат… Когда мы видим, что на значении суммы покупок в 109.11 вдруг округление сработало неведомым образом. Эти баги потом прилетают с боя и их намного сложнее воспроизвести, потому что неясные входные данные. Уж лучше тест сто раз прогонится с разными значениями и 1 раз упадёт и мы это пофиксим, чем сотый клиент, произведя операцию, получит неожидаемый результат или положит систему (такое, как ни странно, тоже бывает)…
    Можно со мной не соглашаться, но именно эти мелкие трудновоспроизводимые, порой критичные баги, больше всего выводят разработчиков, — ещё больше выводят бизнес, потому что их фиксы занимают много времени…

    По поводу разделения unit/функциональные. Если у нас есть модуль А, который вызывает модуль B, тот химичит, отдаёт модулю C. Если мы можем написать функциональный тест с рандомизированными(это я подчёркиваю) входными данными, который войдёт в процессе выполнения в точку А и выйдет из точки C с правильной верификацией, то в 99.9% случаев можно считать, что модуль B покрыт и будет работать правильно без каких-либо unit-тестов. Я никак не отвергаю идею unit-тестирования, просто стараюсь сузить область её применения. Наоборот — я тащусь от Mockito, закрываю моками всё, что можно и стараюсь генерить рандомные значения со стороны заглушек и смотреть, а как вот мой этот функциональный тест, поведёт себя в разрезе работы вот с этими модулями, этими методами…

    Надеюсь, смог сформулировать свою мысль. Если есть вопросы, буду рад ответить


    1. FranciscoSuarez Автор
      06.04.2015 23:03

      Есть модули, которые непременно нуждаются в unit-тестировании. Но везде, где только возможно покрыть модуль сквозным процессом пользователя, лучше покрыть именно процессом, чем со всех сторон юнит-тестами. Быстрее по времени и эффективнее.
      Конечно, если налажен полноценный TDD, то что тут мне спорить)) У всех разные задачи и разные реализации. Я просто делюсь своим опытом.


      1. dougrinch
        07.04.2015 03:07

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


      1. dougrinch
        07.04.2015 03:56
        +1

        что тут мне спорить)) Я просто делюсь своим опытом.
        Ну так в этом вся суть.

        Теперь по делу. На всякий случай уточню, что я пишу с позиции программиста, а не тестировщика. Безусловно, в этом есть своя специфика.

        Сначала про рандомизацию. Я вижу две проблемы:

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

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

        На самом деле, я вот сейчас о чем подумал. Глобально, баги делятся на две категории:
        1. Обработанный случай, но код обработки содержит ошибку.
        2. Про этот случай забыли и его обработки просто нет.

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

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

        Теперь про разделение.

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

        2. У системы может быть много труднодостижимых состояний. В честных функциональных тестах их обычно тяжело протестировать.

        3. Самый важный пункт. Модульные тесты значительно проще. Достаточно создать тариф (хоть из моков), вызвать функцию calculateCost(tariff) и заассертить результат. Все. И если подсчет цены работает неправильно, то абсолютно пофиг как и откуда этот тариф был получен.

        4. Как следствие пред. пункта, модульные тесты работают быстрее, это способствует их более частому запуску.

        Я не против функциональных тестов, но скорее как инструмент проверки стыковки модулей, а не полного тестирования приложения. Грубо говоря, штук 10 на все.

        P.S. Вроде получилось сумбурно и размазано одновременно, прошу за это прощения.


  1. FranciscoSuarez Автор
    07.04.2015 12:05

    Вам не за что просить прощения — конструктивная критика всегда приветствуется.

    По проблемам:
    1. Я за вычисление. Независимое вычисление. Которое проверит ожидаемый результат исходя из этих вычислений
    2. Вероятностные тесты не могут пропустить регрессию. Они делают ровно то же, что и обычные тесты. К примеру, обычный тест нажимает на калькуляторе 2, +, 2, = и проверяет, что результат 4. Рандомизированный тест нажимает a, +, b, = (a+b). Да он берёт на себя логику по проверке суммирования. Но зато, в случае, если существуют значения, на которых сумма по каким-то неведомым причинам не сходится, то это причина для «посмотреть код». Фишка в том, что тесты гонять нужно ровно столько же сколько и раньше, просто в них появляется фактор нестабильности, напрямую отвечающий за отлавливание багов на данных, на которых ни один тестировщик не подумает их искать. Утрируя, 99 случаев из 100 обычный тест и рандомизированный будут вести себя одинаково — цель добиться, чтобы это было в 100 случаях из 100. Не нужно запускать рандомизированные тесты по 100 раз — гоняйте как и раньше, но внимательно следите за теми, которые «иногда» не проходят — поймите причины — найдите проблему.

    Говоря о 109.11, я имел ввиду не точку на пространстве возможных значений, а точку из класса значений, с которыми округление ведёт себя неверно. Таких точек может быть много… Это же метафора…

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

    2. Труднодостижимые состояния (если они не приводят к тому, что ПО останавливает свою работу) некритичны для пользователя, так как они редко по этим сценариям ходят. Закладывать в автомобиль стабилизацию курсовой устойчивости на случай замлетрясения также бессмысленно, как пытаться автоматически достичь этих самых труднодостижимых состояний.

    3. Модульный тесты до тех пор проще, пока автоматические не становятся проще модульных :) Ещё надо создать «кривой» тариф, nullевой тариф, tariff, который меняется из другого потока — такое же тоже может вдруг случиться… Фуyкциональные тесты (рандомизированные) это выловят — если такое когда-нибудь произойдёт. Модульные вы так писать не станете. Модульные проверяют утверждение «эта отвёртка умеет откручивать эти винты», хотя в реальной работе системы могут оказаться другие винты. Да — эта отвёртка в большинстве случаев справится и с ними. Но если появится винт, с которым она не справляется, функциональный тест упадёт, пояснив, что при таком винте и при использовании этой отвёртки винт почему-то в конце не у нас в руках, а по-прежнему закручен в доску. Модульный тест будет по-прежнему зелёным потому что работает с тем винтом, с которым у него всё хорошо.

    4. Да — это отдельный пункт. И самая главная критика автоматических тестов. Но, если не пользоваться sleep-ами, автоматические тесты начинают летать — habrahabr.ru/company/crystal_service/blog/251339/ — в конце этого моего поста есть ссылка на ютюб. Можете посмотреть видео.

    Я на самом деле пытаюсь толкнуть теорию тестирования вперёд и мне очень интересны подобные споры. Я сам в целом разработчик, которого прёт от создания тестовых фрэймворков. Мне не нравятся классические идеи тестирования, потому что они рождались, когда мы жили в мире описанных хорошо или плохо, но всё-таки тех-заданий. Сейчас современное программирование и IT-бизнес, стараются идти от пользователя, развиваются и активно внедряются идеологии Agile. И меня можно было бы поругать, что я вот тут что-то придумываю и предлагаю голословно — но вот уже два проекта внедрены более чем успешно именно на этих идеях. Возможно, они не везде подходят — хочется об этом узнать, конечно. Но проблем с регрессией нет, вылавливаются баги, которые никогда бы не были выявлены никем кроме как пользователями продукта, все счастливы.