Тестирование в высокоэффективных командах — Deloitte

«В современном мире программы управляют всеми сторонами нашей жизни. Мы полагаемся на приложения, которые будят нас утром, организовывают наш день и помогают выполнять нашу работу. Мы общаемся со всем миром, летаем по миру со скоростью 1000 километров в час на высоте 10 километров, а теперь даже ездим без водителя. Правильно спроектированное программное обеспечение, и своевременное устранение ошибок в нем, теперь может означать разницу между жизнью и смертью. Как Инженеры, мы несем ответственность перед клиентами за создание надежного программного обеспечения; и как потребители мы абсолютно зависим от качества ПО.

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

В этой статье рассмотрим «путь Feature» по жизненному циклу безопасной разработки (Secure SDLC), и подробно — типы тестирования «фичи» на этом пути.

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

Описание процессов

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

Кросс-функциональная команда

Наш подход опирается на максимальную автоматизацию тестирования; для этого нужна кросс-функциональная Engineering-команда, в которой Разработчики отвечают за тестирование и автоматизируют свои тесты, а не полагаются на большое количество «ручных» QA-тестов.

Branching-стратегия

Используем GitHub Flow. Предполагается, что main-ветка ВСЕГДА deployable, то есть готова для развертывания. Это требует сдвига влево как можно большего количества тестов — чтобы иметь возможность найти как можно больше дефектов до релиза. GitHub Flow простой и легкий, он ориентирован на команды, которые регулярно выпускают релизы. Нет нужды разбираться с множеством веток для каждого релиза и окружения.

Новые Features передаются в feature-ветку из main-ветки и тестируются в изолированном эфемерном окружении, после чего передаются обратно через Pull Request, проходя peer-review.

Окружения

Возможно, вы заметили, что нет Development-окружения. Это потому что код из любой feature-ветки развертывается в изолированных эфемерных Feature-окружениях. Все ручное и автоматизированное тестирование выполняется здесь, так что мы мержим код в main-ветку только после тестирования.

Это отлично работает на GitHub Flow, потому что мы проверяем, готов ли код к релизу, прежде чем он попадет в main-ветку. Это также означает, что мы можем одновременно тестировать множество Features в их отдельных изолированных окружениях. Feature-окружения создаются с нуля с помощью автоматизации и подхода Infrastructure-as-code. После завершения тестирования, и слияния кода Feature, можно удалять эти окружения.

Далее рассмотрим, какое тестирование выполняется в каждом окружении.

Путь стандартной фичи

Итак посмотрим на «Feature’s Journey», то есть на путь, который проходит код новой фичи по SSDLC-циклу. Вот карта этого пути:

Локальная разработка

Новый код разрабатывается в новой feature-ветке одним или несколькими Разработчиками. Могут применяться такие техники, как Test-Driven Development и парное программирование.

На этом этапе я ожидаю, что все новые автотесты будут написаны и переданы одновременно с кодом, который они тестируют. Разработчики (почти) всегда обязаны писать юнит-тесты при создании фич. Я ожидаю от всех своих команд 80-90% покрытия юнит-тестами — никаких отговорок! Покрытие очень важно для того, чтобы код можно было безопасно адаптировать и рефакторить в будущем, не нарушая существующей функциональности. 

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

В зависимости от функциональности разрабатываемой фичи, разработчик также пишет интеграционные тесты, тесты E2E/UI и тесты производительности.

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

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

Pull Request

Как только код готов, разработчик создает Pull Request (PR), чтобы слить код в main-ветку. На этом этапе происходит автоматическое уведомление других Инженеров команды, чтобы они предоставили рецензию кода — Peer Review и Фидбек.

Пир-ревью считается завершенным, только если:

  • По крайней мере 1 человек проверил и «принял» новый код
  • Все комментарии по коду помечены как «решённые»
  • Успешный билд непрерывной интеграции, и автоматизированные тесты пройдены
  • Проведены все проверки качества (Quality Gates)
  • Код привязан к тикету/PBI/истории(story).

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

Непрерывная интеграция

Каждый раз, когда проводится PR-ревью, должна автоматически запускаться сборка Continuous Integration нового кода. Именно здесь будет происходить большая часть автоматизированного тестирования, включая все новые тесты, добавленные Разработчиком в свой коммит.

Если какой-либо из тестов упадет, сборка считается неудачной и завершение PR блокируется. Я ожидаю от команд, что будут выполняться следующие автоматизированные тесты:

Юнит-тесты 

Юнит-тесты должны тестировать код (как правило, это Классы и Функции) в изоляции. Любые зависимости должны быть «закрыты» стабами или моками, чтобы обеспечить надежное поведение модуля. Приверженцы «чистого кода» считают, что один тест должен охватывать всегда только один класс или функцию; я менее придирчив в этом вопросе, но в целом к этому стоит стремиться. При выполнении юнит-тестов мы отслеживаем их покрытие по всему коду. Сборка должна иметь покрытие кода не менее 80-90 % для всего нового кода.

Интеграционные и API

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

Quality Testing и статическое тестирование безопасности (SAST)

Эти тесты обычно включают в себя использование внешних инструментов для проверки кода, на:

  • Code Smells
  • Баги
  • Полноту тестового покрытия
  • Плохие практики
  • Security Hotspots
  • Дублирование кода

Лично я являюсь большим поклонником SonarQube. Это инструмент для Quality Testing, однако он может выполнять и множество SAST-проверок. Замечательной особенностью SonarQube является то, что он может выполнять проверки только нового кода, что позволяет легко внедрять его в легаси-приложения, где всегда много старого проблемного кода, который разработчики не могут или не хотят сейчас исправлять.

Как только SonarQube встраивается в процессы команды, он очень сильно улучшает результаты работы этой команды.

Проверка на соответствие стайлгайдам и линтинг

Я обнаружил, что 90 % комментариев при PR-рецензировании кода связаны с вопросами по стилю кода и соглашений об именовании. Это может сильно отвлекать разработчиков и отнимать время. Наличие согласованных стандартов и руководств по стилю кода (стайлгайдов) для команды может стать реально эффективным способом уменьшить эти проблемы в процессе рецензирования.

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

  • .editorconfig: Руководство по стилям в Visual Studio
  • dotnet format: Можно использовать для анализа соответствия и автоматического исправления отклонений от стиля
  • ESLint: линтинг Typescript-сценариев и автоматическое исправление
  • Hadolint: Линтинг Dockerfile
  • Helm Lint: Линтинг Helm-диаграмм

Тестирование архитектуры

Помимо тестирования стиля кода, мы также проверяем и соблюдение принципов архитектуры. Фреймворки для тестирования архитектуры, такие как ArchTest и NetArchTest, используем для проверки code layering, зависимостей, и соглашений об именовании.

public class CleanArchitectureTests : BaseTests
{
    [Fact]
    public void CleanArchitecture_Layers_ApplicationDoesNotReferenceInfrastructure()
    {
        AllTypes.That().ResideInNamespace("CleanArchitecture.Application")
        .ShouldNot().HaveDependencyOn("CleanArchitecture.Infrastructure")
        .AssertIsSuccessful();
    }

    [Fact]
    public void CleanArchitecture_Layers_CoreDoesNotReferenceOuter()
    {
        var coreTypes = AllTypes.That().ResideInNamespace("CleanArchitecture.Core");

        coreTypes.ShouldNot().HaveDependencyOn("CleanArchitecture.Infrastructure")
            .AssertIsSuccessful();

        coreTypes.ShouldNot().HaveDependencyOn("CleanArchitecture.Application")
            .AssertIsSuccessful();
    }

    [Fact]
    public void CleanArchitecture_Repositories_OnlyInInfrastructure()
    {
        AllTypes.That().HaveNameEndingWith("Repository")
        .Should().ResideInNamespaceStartingWith("CleanArchitecture.Infrastructure")
        .AssertIsSuccessful();

        AllTypes.That().HaveNameEndingWith("Repository")
            .And().AreClasses()
            .Should().ImplementInterface(typeof(IRepository<>))
            .AssertIsSuccessful();
    }

    [Fact]
    public void CleanArchitecture_Repositories_ShouldEndWithRepository()
    {
        AllTypes.That().Inherit(typeof(IRepository<>))
            .Should().HaveNameEndingWith("Repository")
            .AssertIsSuccessful();
    }
}

Сканирование уязвимостей и проверка опенсорсного кода

На этом этапе обычно используются сторонние CLI-инструменты для сканирования кода и образов контейнеров на предмет уязвимостей в системе безопасности и рисков, связанных с опенсорсным кодом (OSS).

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

Вот несколько достойных инструментов:

  • Snyk
  • Aqua Trivy
  • Docker Scout
  • Prisma Cloud/Twistlock

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

Тестирование фич

Если сборка в CI прошла успешно, то feature-ветка будет автоматически развернута в совершенно новом Feature-окружении. В этом окружении проводим дополнительные автоматизированные и ручные тесты.

Сквозные UI-тесты

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

Также используем инструменты SpecFlow и JBehave, которые позволяют писать тесты, используя спецификации в BDD-виде, и преобразовывать их в этапы-Steps. Дело в том, что если у вас есть большое количество шагов, то бизнес-аналитики и тестировщики могут писать спецификации к новым тестам даже без знания языков программирования.

@weather_cleanup
Feature: Weather Forecast

Weather Forecast page shows a table of weather forecasts 
and allows new forecasts to be generated.

Scenario: 1 Navigate to Weather Forecast page
	Given a user is on the Home page
	When Weather Forecast page is opened
	Then Weather Forecast page is open

Scenario: 2 Generate a Weather Forecasts
	Given a user is on the Weather Forecast page
	When 'London' location is selected
	And a weather forecast is generated
	And a weather forecast is generated
	Then '2' weather forecasts present

Scenario: 3 Generate Weather Forecasts prompt shown
	Given a user is on the Weather Forecast page
	When 'Mumbai' location is selected
	Then Generate prompt is visible
	And '0' weather forecasts present

Лучшим фреймворком для тестирования пользовательского интерфейса на данный момент является Playwright. Если вы все еще используете Selenium для UI-тестирования, обязательно обратите внимание на Playwright — он намного лучше.

Одна из многих замечательных особенностей Playwright — возможность генерации кода автотестов:

PowerShell.exe -ExecutionPolicy Bypass -File .\tests\CleanArchitecture.AcceptanceTests\bin\Debug\net7.0\playwright.ps1 codegen https://localhost:44411/

Динамическое тестирование безопасности приложений (DAST)

DAST — процесс анализа фронтенда веб-приложения с целью поиска уязвимостей путем симуляции атак. Если у нас уже есть автоматизированные UI-тесты, то мы можем подключиться к ним и использовать их для выполнения DAST-тестирования.

Инструменты типа OWASP Zed Attack Proxy (ZAP) можно использовать для проксирования UI-тестов при их запуске. ZAP проанализирует запросы во время выполнения тестов и выполнит различные атаки на основе полученных данных. В конце он предоставит отчет с указанием уязвимостей и рекомендациями по их устранению.

Ручное исследовательское тестирование

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

QA

После завершения PR-ревью и слияния нового кода в main-ветку можем удалять Feature-окружение и деплоить в QA-окружении. В идеале все же надо еще раз запустить все автотесты на случай, если после слияния кода возникнут какие-либо проблемы.

Возможно, здесь понадобится дополнительное ручное исследовательское тестирование в QA-окружении. Опять же, это зависит от качества автотестов и вашей ситуации.

Staging-окружение

Я ожидаю от команд, что после развертывания в Staging-окружении будет выполнено нужное количество регрессионных UI-автотестов. Это также хорошее время для проведения приемочного тестирования (UAT) конечными пользователями, если оно вам нужно.

Как правило, в Staging-окружении проводится и тестирование на проникновение (pentesting). Тестирование на проникновение это почти то же что и DAST, с той лишь разницей, что проводится вручную.

UAT-тестирование и Pentesting нужны не для каждого релиза. Частота их проведения зависит от команды и функциональности релиза.

Нагрузочное окружение

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

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

Тесты производительности

Существует несколько типов тестирования производительности, которые релевантны в наших проектах: нагрузочное тестирование, тестирование выносливости и стресс-тестирование. Я написал об этом статью Mastering API Performance Testing with k6, Grafana and WireMock.

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

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

Production

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

На этом наш рассказ о «путешествии по пути фичи» подходит к концу. Но тестирование продолжается: так как ландшафт угроз постоянно меняется по мере обнаружения новых методов кибератак, то даже после деплоя кода на Production важно регулярно проводить сканирование уязвимостей, DAST и тесты на проникновение, кода и окружения.

Итак, я описал довольно полный набор тестов, и понятно, что у каждой команды найдутся варианты, которые подойдут именно ей. Надеюсь, я дал вам несколько идей для внедрения в вашей команде.»

Источник (member-only)

Линкедин автора


Божественный канал по бизнес-анализу

Project-менеджер

Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

🔥 Популярное

💬 Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас