При рассмотрении термина «осмысленное тестирование» он выглядит как довольно странная абстракция, распространяющаяся на всю цепочку работы с программным обеспечением – от постановки задачи на разработку до деплоя. Что же значит слово «осмысленный» в данном контексте?

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

Пирамида тестирования

Я думаю, что все вы знакомы с пирамидой тестирования. В блоге Мартина Фаулера есть хорошее объяснение для данного понятия от Хэма Вока. Если вы согласны с тем, что там сказано, то позволю себе обратить внимание на одном из предложений публикации.

«Несмотря на то, что концепция тестовой пирамиды существует довольно давно, команды все еще пытаются воплотить ее на практике».

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

При обработке запроса «пирамида тестирования» в Google вы можете увидеть что-то вроде этого.

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

Abstract Testing Pyramid
Abstract Testing Pyramid

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

Стилистическое и программное тестирование кода

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

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

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

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

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

Интеграционное тестирование

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

Сейчас существует большое количество инструментов, используемых для создания своего стека интеграционного тестирования. Отмечу, эволюцию Swagger, Postman или такой многообещающий облачный продукт как Azure API Management. Последними, но не менее важными, я хотел бы упомянуть известные библиотеки и инструменты типа Faker и прочих.

На этом этапе также должны выполняться проверки зависимости на безопасность, даже если это будет служба от поставщика VSC, управляемая внешняя служба SaaS или инструмент с открытым исходным кодом DependencyTracker.

e2e тестирование

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

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

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

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

Expect true to be “truthy”

В заключении я хотел бы начать с пояснения смысла названия этого раздела: «Expect true to be “truthy”. Я думаю, что каждый причастный к разработке делает все необходимое, чтобы иметь высокий уровень QA (насколько это возможно). При этом мы по-прежнему сфокусированы на лучших практиках, а не на осмыслении того, как они реализуются. Именно поэтому тратится время на устранение преград, которые в итоге вынуждают нас делать то, что не приносит никакой пользы.

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

Первоначально опубликовано в ТГ канале QA team

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


  1. amarao
    11.02.2022 12:38
    +1

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


    1. hel1n Автор
      11.02.2022 12:41

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


      1. amarao
        11.02.2022 14:17

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


        1. hel1n Автор
          11.02.2022 15:08

          Жесткие правила линтера иногда защищают от дефектов
          например жесткая проверка типов в ts (убрать всякие any)


          1. amarao
            11.02.2022 15:58

            Тогда это уже не линтер. Есть масса анализаторов кода, но называть их "линтеры", это всё равно, что называть компьютер под столом "процессором".

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


            1. hel1n Автор
              11.02.2022 16:25

              Статический анализ кода включает lint-еры

              а форматировать код в единый стиль - это инструмент prettier


    1. werevolff
      13.02.2022 06:16

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


      1. amarao
        13.02.2022 18:15

        Юнит-тесты пишутся программистами. Для программистов. Даже если QA репортит "клиент теряет 100500 денег из-за того, что вы неправильно умножаете", то:

        • нужен тест, который проверит, что клиент не теряет 100500 денег в специфичных условиях. Это задача QA.

        • программист ищет из-за чего там не туда поделилось, и если это не баг в реализации требований, а баг в самом коде (например, ошибочная конвертация float->int перед умножением), то он пишет тест. Этот тест проверяет найденную ошибку, и его задача, как и задача любого хорошего теста - проверять сохраение инварианта. Этот тест не решает бизнес-задачу, он нужен для программистов, чтобы сохранить инвариант.

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

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


        1. werevolff
          13.02.2022 23:57

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

          Не считали, так я помогу: если есть QA специалист (хотя бы, один) в команде, значит, заказчик уже тратит деньги на интеграционные тесты. Просто, когда программист один, без QA, потери от регресса превышают затраты на отдельного тестировщика. Собственно, парам-пам-пам, для этого и нанимают QA. А число QA разработчиков в штате обратно пропорционально test coverage. То, что вы не умеете быстро писать тесты, или сразу выдавать легко тестируемый код, это только ваша проблема. При нормальном TDD никаких 100500 часов потерь на тесты нет, и быть не может. Уровень интеграционных тестов в разработке и QA - разный. А специалисты, орущие про потери заказчика при написании тестов, это, как-правило, люди, готовые потратить день на написание кнопки, длительное тестирование её функционала на продакшене, а потом - неделю на её переписывание из-за отказа QA принимать работу.

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


  1. Kalcefer
    11.02.2022 15:08
    +1

    Грань между integration и e2e вполне можно размыть, особенно в маленьких командах QA.Так, как вы написали если от юнит тестов к интеграционным тестам мы переходим. То к e2e мы вынужденно перетикаем.


    1. hel1n Автор
      11.02.2022 15:18

      Согласен, в реальной жизни именно так