В прошлый раз мы сказал , как доказать всем участникам проекта, что тестирование — дело полезное.
Надеемся, что аргументы оказались убедительными.
Теперь мы можем поговорить о том, как подойти к созданию, проектированию, классификации и оценке тестов.
Пирамида тестирования
Эффективное распределение тестов с точки зрения их автоматизации можно представить в виде пирамиды.
Большая часть функциональности программного обеспечения покрывается простыми модульными тестами, а для остальной функциональности создаются более сложные.
Если перевернуть эту пирамиду, мы получим воронку с множеством разных ошибок на входе и небольшим количеством гейзенбагов на выходе.
Давайте подробнее рассмотрим каждую группу.
- Модульное или блочное тестирование работает с конкретными функциями, классами или методами отдельно от остальной системы.
Благодаря этому при возникновении ошибки можно поочередно изолировать каждый блок и определить, где ошибка.
В эту группу входит поведенческое тестирование.
По сути он похож на модульный, но предполагает строгий регламент написания тестового кода, который регламентируется набором ключевых слов.
- Интеграционное тестирование сложнее модульного, так как проверяет взаимодействие кода приложения с внешними системами.
Например, тесты пользовательского интерфейса EarlGrey отслеживают, как приложение взаимодействует с ответами API сервера.
- Приемочное тестирование проверяет правильность работы функций, описанных в технических характеристиках.
Он состоит из наборов крупных кейсов интеграционного тестирования, которые расширяются или сужаются с точки зрения тестовой среды и конкретных условий запуска.
- Тестирование пользовательского интерфейса проверяет, насколько интерфейс приложения соответствует спецификациям дизайнеров или запросам пользователей.
Оно включает в себя снапшот-тестирование, когда скриншот приложения попиксельно сравнивается с эталонным.
При таком способе невозможно закрыть все приложение, так как сравнение двух изображений требует много ресурсов и нагружает тестовые серверы.
- Ручное или регрессионное тестирование остается после автоматизации всех остальных скриптов.
Этими случаями занимаются QA-специалисты, когда нет времени писать UI-тесты или нужно отловить плавающую ошибку.
Из-за этого снижается эффективность тестирования, и от этого необходимо избавляться: отходить от ручных тестов и увеличивать количество юнит-тестов.
Юнит против пользовательского интерфейса
По сравнению с тестами пользовательского интерфейса модульные тесты выполняются быстрее и требуют меньше времени на разработку.Их можно запускать локально, без мощных ферм или отдельных устройств.
Обратная связь от модульных тестов происходит во много раз быстрее, чем от UI-тестов.
Изменения в файле API или XML приводят к массовому сбою тестов пользовательского интерфейса; их нужно каждый раз переписывать.
На этом фоне важным преимуществом модульных тестов является большая надежность.
С точки зрения покрытия кода модульные тесты более эффективны, но они не могут полностью покрыть тестирование.
Необходимо постоянно поддерживать баланс, при котором юнит-тесты охватывают базовые случаи, а UI-тесты решают более сложные задачи.
Важно понимать, что тесты высокого уровня сигнализируют о неисправленных ошибках в тестах более низких уровней, поэтому при появлении ошибки, например, в производственном коде, следует сразу делать соответствующий модульный тест. Когда баги воскрешаются, это раздражает гораздо больше, чем когда они обнаруживаются впервые.
Требования к тестовому коду
Помимо известных принципов SOLID, определяющих качество и красоту кода, при программировании тестов необходимо учитывать еще два требования: скорость и надежность.
Их можно достичь, следуя пяти основным принципам, известным под общим названием FIRST.
- F – Быстро .
Хорошие тесты дают максимально быстрый ответ. Сам тест, его установка в среду и очистка ресурсов после выполнения должны занимать несколько миллисекунд.
- Я - изолирован.
Тесты должны быть изолированными.
Тест выполняет проверку самостоятельно, а все данные для него берутся из среды и не зависят от других тестов и тестовых модулей.
Приятный бонус для тех, кто следует этому принципу: порядок тестов не важен, и их можно запускать параллельно.
- Р – Повторяемый.
Тесты должны иметь предсказуемое поведение.
Тест должен давать четкий результат независимо от количества повторений и окружающей среды.
- S – Самопроверка.
Результат теста должен быть очевиден и отображаться в каком-нибудь очевидном журнале.
- Т – Тщательно/Своевременно.
Тесты должны разрабатываться параллельно с кодом, хотя бы в рамках одного пул-реквеста.
Это гарантирует покрытие боевого кода, а также актуальность самих тестов и то, что их не потребуется в дальнейшем модифицировать.
Для этого важна синхронность, отсутствие ожидания внешней реакции и внутренних тайм-аутов.
Что должны охватывать тесты?
В рамках TDD (test-driven development) сегодня возникли две школы тестирования.В Чикагской школе упор делается на результаты, полученные от тестируемых занятий и методов.
В Лондонской школе тестирование фокусируется на поведении и предполагает использование макетов предметов.
Допустим, у нас есть класс, который умножает два числа, скажем, 7 и 5. Чикагская школа просто проверяет, что результат равен 35 — ее не волнует, как мы это узнаем.
Лондонская школа говорит, что нам нужно заблокировать внутренний калькулятор, который существует в нашем классе, проверить, что он вызывается с правильным набором методов и данных, и убедиться, что он возвращает заблокированные данные.
В школах Чикаго тесты проводятся с использованием черного ящика, а в школах Лондона — с использованием белого ящика.
В разных тестах имеет смысл использовать оба метода.
Почему 100%-ное покрытие тестами невозможно?
Даже если вы покроете 100% кода тестами, вы все равно не сможете гарантировать отсутствие ошибок.А стремление добиться 100% покрытия только мешает работе: разработчики начинают стремиться к этой цифре, создавая тесты ради показателей.
О качестве тестов говорит не уровень покрытия, а более простые факты: до конечного продукта доходит мало ошибок, а при закрытии найденной ошибки новые не появляются.
Уровень покрытия лишь сигнализирует о том, что он должен по определению — есть ли у нас непокрытые участки кода или нет. В следующей статье нашей серии о тестировании мы перейдем к проектированию, разберем различные нотации тестирования и типы тестовых объектов, а также требования к качеству тестового кода.
Теги: #Управление разработкой #Тестирование ИТ-систем #тестирование с использованием #tdd
-
Dell Vostro Серии V3500-Cto1
19 Oct, 24 -
Метафоры
19 Oct, 24