Разделы портала

Онлайн-тренинги

.
Ретроспективные уроки автоматизации: принцип трех А
22.04.2019 00:00

Автор: Виктор Славчев (Viktor Slavchev)
Оригинал статьи: https://mrslavchev.com/2018/06/26/hindsight-lessons-about-automation-the-triple-a-principle/
Перевод: Ольга Алифанова.

Разделавшись с тем, почему автоматизация важна, и где нужно сосредотачивать усилия по автоматизации, перейду к более специфичным советам, связанным с тем, как создавать полезные и простые в поддержке тесты. В этот раз мы сконцентрируемся на принципе ААА. Конечно, как и прочие статьи в этой серии, эта описывает мой личный опыт и знания. Если вам есть, чем дополнить – пожалуйста, сделайте это.

Принципы автоматизации

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

К чему эти основы?

Возможно, люди с опытом в автоматизации уже закатывают глаза со словами "Чувак, это какой-то детский сад для автоматизаторов" – и это правда, принцип трех А самый базовый из всех возможных. Это основной принцип не только для автоматизации, но и для юнит-тестирования. Я рассказываю о нем, так как наблюдаю людей, концентрирующихся на более продвинутых темах, вроде параллельного запуска тестов, хабов, контейнеров, облачности, Page Object, Фабриках, ScreenPlay… Все это круто, но предназначено для того, чтобы стать вишенкой на торте вашего фреймворка. Если вы не знакомы с базовыми принципами, то вы строите ваш фреймворк на шатком основании. Поэтому я предпочитаю начать с самых основ и предоставить информацию об основных принципах, а не о фреймворках и паттернах, которые могут измениться в любой момент.

Любой принцип, в сущности, помогает решить или избежать грядущих проблем.

В чем проблема?

Одна из наиболее обсуждаемых тем – это нестабильные проверки, а также проверки с неточными и ненадежными результатами. Как я говорил в предыдущей статье, термин "нестабильные проверки" – это, в сущности, попытка переложить ответственность с тестировщика на инструмент, окружение, фреймворк и что угодно еще. По сути, нестабильные проверки – это ошибка в тест-дизайне. Задача принципа ААА – сделать проверки более гибкими и более однозначными в плане выполняемых ими действий.

Принцип ААА

Принцип трех А означает подготовку (Arrange), действие (Act) и оценку результата (Assert). Это значит, что любой тест должен состоять из трех логических компонентов:

Подготовка: настройка окружения.

Действие: выполнение действия в интересах вашего теста.

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

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

Давайте подробнее рассмотрим каждую стадию.

Подготовка (Arrange)

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

  • Импорт желаемых тестовых данных.
  • Открытие Chrome Driver.
  • Навигация на страницу "/basket".
  • Авторизация в качестве пользователя Х.
  • Перевод денег в количестве Х.

Почему это важно?

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

Действие (Act)

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

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

Это и есть наше действие. Очевидно, что мы должны явно описывать наши действия. Вот неплохие примеры:

  • Я меняю страну пользователя и хочу убедиться, что процент НДС верно указан.
  • Я добавляю предмет в корзину и проверяю, увеличилась ли общая сумма точно на стоимость добавленного предмета.
  • Я меняю тип клиента с "личного профиля" на "корпоративный" и убеждаюсь, что отображено дополнительное поле "Название компании".

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

Оценка (Assert)

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

  • Не используйте верификацию. Верификация – нечто вроде безалкогольного ассерта, когда тесты не падают и продолжают выполняться. С моей точки зрения, ваш дизайн плох, если вам это необходимо.
  • Создавайте значимые сообщения о падениях проверки. Это немного нудно, но зато спасет вашу задницу. Не полагайтесь исключительно на результат теста, чтобы узнать, что пошло не так. Вы автор проверки, вы знаете бизнес-логику и контекст, облегчите себе жизнь.
  • Старайтесь избегать AssertTrue/False. Не то чтобы они были бесполезны, но когда они падают, получаются идиотские ошибки "Не удалось убедиться, что true соответствует false", что, конечно, крайне полезная для нас информация. Если у вас нет выбора, попробуйте составить более внятное сообщение об ошибке.
  • AssertEquals – довольно мощная штука. Знаю по опыту, что AssertEquals сильно помогает в дебаге падений, так как дает и ожидаемый, и фактический результат. Если вы можете использовать его – это сильно вам поможет. Однако это не серебряная пуля, потому что иногда фактический результат будет исключением с тысячей строк внутри.
  • Один ассерт на тест. Да, я знаю, что можно добавить и больше, но это не значит, что это полезно. Мы уже говорили о том, что тесты должны быть однозначными, что также означает, что при падении тест должен сразу же сообщать, что конкретно пошло не так. Когда тест падает, я хочу иметь возможность сказать "А, сервис вернул неверное значение", а вовсе не "Хм, давайте откроем тест, перезапустим его десять раз в режиме дебага и посмотрим, какой из десяти ассертов упал".
  • Посмотрите, как падают ваши тесты. К моему удивлению, существуют люди, коммитящие тесты, отказа которых они никогда не видели. Это очень забавно, потому что все мы твердим о том, что баги – это нормально, что никто не пишет идеальный код с первого раза, и не менее тем – автоматизаторы относятся к своему коду так, как будто он написан лично господом Богом. Что за херня? Тестируйте ваши тесты, заставьте их упасть – иногда может оказаться, что вы полагаетесь на какие-то допущения и предположения, даже не осознавая этого. Мы способны крайне успешно обманывать самих себя.

Итак, как же будет выглядеть хороший тест?

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

public function checkVatPercentageAfterUpdate(){
   //Arrange, might be in @before or @beforeMethod
Importer.importTestData(data);
Client testClient = new Client(username, password);
LoginAsClient(username, password);
 
//Act
NavigateTo(Profile)
SelectCountry("Ireland")
SubmitProfile();
string actualPercentage = GrabDataFromField(vatPercentage);
 
//Assert
AssertEquals(20%, actualPercentage, "The actual percentage of profile, mismatches the expected result")
}

Что может пойти не так?

Принцип ААА означает, что у вас должна быть одна подготовка, одно действие и одна оценка. Я не люблю концепцию end-to-end автоматизации, помимо всего прочего, за то, что они устраивают из "А" бесконечную цепочку – Arrange, Act, Assert, Act, Act, Assert, Assert (чего-нибудь другого), Assert (что страница все еще страница), и так далее.

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

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

Обсудить в форуме