Чуть больше про Pytest. Урок 2

Что разберем:

  1. Что такое предусловие, постусловие?
  2. Что такое фикстуры в pytest? Как мы можем их использовать?
  3. Какие аргументы принимают фикстуры?
  4. Зачем нужен yield в фикстурах?
  5. Что такое conftest.py файл?
  6. Что такое веб элемент?
  7. Какую информацию о веб элементе мы можем получить?

Предусловия, Постусловия Предлагаю немного углубиться в pytest и поговорить о фикстурах, но перед этим на нужно обратиться к теории тестирования.

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

Приведение системы в нужное состояние перед началом тестирования называется “Предусловие” (Precondition). Это набор условий или действий, которые должны быть выполнены или соблюдены перед началом исполнения тестового кейса. Возврат системы в исходное или известное состояние после тестирования называется “Постусловие” (Postcondition). Это то, что тестировщик делает после выполнения теста, чтобы вернуть систему в такое состояние, которое позволит другим тестам быть выполненными без остаточного влияния от предыдущего теста. Эти концепции особенно важны для автоматизированного тестирования, где тесты могут выполняться в произвольном порядке, и нам нужно быть уверенными в их независимости и повторяемости.

Предлагаю взглянуть на пример тест кейса использующего постусловие и предусловие

    Тестовый кейс : 001
    Название: Добавление товара в корзину
    Описание: Проверка функционала добавления товара в корзину на сайте интернет-магазина.
    Предусловие:
    Пользователь зарегистрирован и вошел в свой аккаунт.
    Корзина пуста.
    Товар в наличии.
    Шаги:
    Перейти на страницу товара.
    Нажать "Добавить в корзину".
    Открыть корзину.
    Ожидаемый результат:
    Товар отображается в корзине с правильным наименованием, ценой и количеством.
    Постусловие:
    Удалить товар из корзины.
    Вернуть количество товара на склад (если применимо).

А теперь предлагаю взглянуть на вариант без постусловия и предусловия:

    Тестовый кейс : 002
    Название: Изменение пароля пользователя
    Описание: Проверка возможности смены пароля в профиле пользователя.
    Шаги:
    Войти в профиль пользователя.
    Ввести новый пароль.
    Подтвердить ввод нового пароля.
    Ожидаемый результат:
    Пользователь получает уведомление о том, что пароль успешно изменен.

Проблемы и последствия отсутствия предусловий и постусловий:

  1. Не заданное начальное состояние: Неясно, какой пользователь и какой у него изначальный пароль, что может привести к ошибкам при входе или использовании нецелевого аккаунта.
  2. Изменение состояния системы: После теста пароль пользователя изменен, что может нарушить другие тесты, использующие этот аккаунт. Влияние на реальные данные: Если тест проводится на реальных данных, это может влиять на реального пользователя, возможно, блокируя его доступ.
  3. Отсутствие отката: Без возвращения пароля к исходному состоянию тестовое окружение остается измененным, что может вызвать проблемы при последующем тестировании. Надеюсь, этот пример показывает важность предусловий и постусловий в тестировании.

Супер, мы разобрались что такое постусловие, предусловие и зачем же они нужны нам в тестировании.

Введение в фикстуры В документации Pytest мы можем найти страницу посвященную анатомии теста Ссылка: https://pytest.org/en/7.4.x/explanation/anatomy.html#test-anatomy

Предлагаю разобрать небольшой пример. Ссылка на пример в Github:

В файле registration_system.py находится класс имитирующий логику работы системы регистрации

Логика работы:

  1. Инициализация: При создании объекта этого класса инициализируется пустой словарь self.users. Этот словарь будет хранить информацию о пользователях. Ключом словаря является электронная почта пользователя, а значением - другой словарь с именем, номером телефона и email’ом.
  2. Регистрация пользователя: Метод register принимает имя, email и номер телефона пользователя. Если пользователь с указанным email уже существует в системе, метод возвращает ошибку. В противном случае, новый пользователь добавляется в систему, и метод возвращает успешное сообщение.
  3. Удаление всех пользователей: Метод delete_all_users очищает словарь self.users, удаляя всех пользователей из системы.
  4. Удаление пользователя по email: Метод delete_user_by_email принимает email пользователя, который необходимо удалить. Если такой пользователь существует, он удаляется из системы. Если пользователя с таким email нет, возвращается сообщение об ошибке.
  5. Просмотр всех пользователей: Метод view_all_users просто возвращает текущий словарь пользователей, позволяя просмотреть зарегистрированных пользователей.

В файле test_registration_system.py находится 2 теста с использованием pytest

Я подготовил ручные тест кейсы, которые впоследствии автоматизировал. Давайте сначала разберем ручные тесты:

    Тестовый кейс : 001
    Название: Регистрация пользователя без предусловий и постусловий
    Описание: Проверка функционала регистрации нового пользователя.
    Шаги:
    1.1 Создать объект класса RegistrationSystem.
    1.2 Вызвать метод register с параметрами: "Алекс", "alex@example.com", "+1234567890".
    1.3 Вызвать метод view_all_users и проверить наличие пользователя с данным email в системе.
    Ожидаемый результат:
    Пользователь с email "alex@example.com" присутствует в системе.

Теперь тест кейс с использованием предусловия и постусловия:

    Тестовый кейс : 002
    Название: Регистрация пользователя с предусловиями и постусловиями
    Описание: Проверка функционала регистрации нового пользователя с учетом начального состояния системы и восстановления исходного состояния после теста.
    Предусловие:
    Система инициализирована, база данных пуста.
    Шаги:
    2.1 Создать объект класса RegistrationSystem.
    2.2 Вызвать метод register с параметрами: "Алекс", "alex@example.com", "+1234567890".
    2.3 Вызвать метод view_all_users и проверить наличие пользователя с данным email в системе.
    Ожидаемый результат:
    Пользователь с email "alex@example.com" присутствует в системе.
    Постусловие:
    Удалить всех пользователей из системы, вызвав метод delete_all_users.

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

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

Теперь предлагаю разобрать код наших тестов

Данный код представляет собой набор тестов, написанных с использованием библиотеки pytest, для класса RegistrationSystem, который вы рассмотрели ранее. Основная цель тестов — проверить корректность регистрации новых пользователей в системе.

Импорты:

  1. pytest: используется для написания и запуска тестов.

  2. RegistrationSystem: основной класс из внешнего файла (registration_system.py), который мы будем тестировать.

  3. Фикстура init_system: Фикстуры в pytest позволяют задавать начальные условия для тестов и выполнять некоторые операции после завершения теста. В данной фикстуре: Создается объект system класса RegistrationSystem. С помощью yield, этот объект передается тесту, который будет использовать фикстуру. После завершения теста (после строки с yield) выполняется метод delete_all_users(), который удаляет всех пользователей из системы. Это является постусловием, которое гарантирует, что после завершения теста система возвращается к исходному состоянию.

  4. Тест test_registration_without_pre_post_conditions: В этом тесте: Создается новый объект system класса RegistrationSystem. Регистрируется новый пользователь с заданными данными. Проверяется наличие зарегистрированного пользователя в системе с помощью assert. Если условие не выполняется, тест будет считаться проваленным.

  5. Тест test_registration_with_pre_post_conditions: В этом тесте: Используется фикстура init_system, чтобы получить объект системы с примененными предусловиями и постусловиями. Аналогично предыдущему тесту, регистрируется новый пользователь и проверяется его наличие в системе.

Логика работы: При запуске тестов с помощью pytest, оба тестовых метода будут выполнены. Перед запуском test_registration_with_pre_post_conditions будет выполнена фикстура init_system, инициализирующая систему. После завершения каждого теста, который использовал фикстуру, будет выполнено постусловие из фикстуры (очистка списка пользователей). Если какой-либо из assert утверждений не выполнится, pytest пометит соответствующий тест как проваленный. Ну вот наконец то мы дошли до фикстур давайте разберемся что же такое фикстуры, потренируемся в написании фикстур на более простом примере и вернемся к нашему коду с полным пониманием происходящего

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

Определение фикстуры производится с помощью декоратора @pytest.fixture. Фикстуры можно затем внедрять в функции теста как аргументы. Давайте глянем на простой пример использования фикстуры

Пример так же можно найти в папке lesson2 -> в файле test_simple_example.py

Импорт необходимых библиотек: import pytest from faker import Faker

Здесь импортируются две библиотеки: pytest и Faker (для генерации фейковых данных). Определение фикстуры:

    @pytest.fixture 
    def fake_email(): 
        fake = Faker() 
        return fake.email()

@pytest.fixture - это декоратор из библиотеки pytest, который указывает, что следующая функция является фикстурой. Фикстуры в pytest используются для предоставления некоторых данных или состояний для тестов. Внутри фикстуры fake_email создается экземпляр объекта Faker (назовем его fake). С помощью метода fake.email() генерируется фейковый email. Фикстура возвращает сгенерированный фейковый email, который будет доступен для тестов, которые используют эту фикстуру.

Тестовая функция:

def test_email_format(fake_email): 	
# Проверка, что в email есть символ '@'
assert "@" in fake_email 
# Проверка, что email содержит точку после символа '@' 
assert "." in fake_email.split('@')[1] 
# Проверка, что email не пустой 
assert len(fake_email) > 0

Функция test_email_format является тестовой функцией, что видно по префиксу test_. Она принимает один аргумент, fake_email, который предоставляется фикстурой с тем же именем.

Внутри тестовой функции выполняются три проверки (assertions) для фейкового email:

  1. Проверяется наличие символа “@” в email.
  2. Проверяется наличие символа “.” в доменной части email (после символа “@”).
  3. Проверяется, что email не пустой. Если все проверки проходят без ошибок, то тест считается успешным.

Теперь предлагаю разобраться с тем какие аргументы может принимать фикстура и как это может помочь нам в работе

Аргументы фикстур в Pytest:

  1. autouse: Если аргумент autouse установлен в True, фикстура будет автоматически применена ко всем тестам, которые находятся в той же области видимости. Вам не нужно явно указывать фикстуру в аргументах теста. python

Пример в файле test_autouse_example.py. Когда мы используем autouse мы должны быть достаточно осторожны

  1. scope: Аргумент scope определяет область видимости фикстуры: как часто она будет создана. Возможные значения: function (по умолчанию): Фикстура запускается для каждого теста отдельно. class: Фикстура запускается один раз для класса и используется для всех тестов внутри класса. module: Фикстура запускается один раз для модуля и используется для всех тестов внутри этого модуля. session: Фикстура запускается один раз за сессию и используется для всех тестов в течение этой сессии.

  2. params — это ещё один важный атрибут для фикстур в pytest. Он позволяет параметризовать фикстуры. Это особенно полезно, когда вы хотите запустить один и тот же тест (или набор тестов) с разными начальными условиями или данными, предоставленными фикстурой.

yield в контексте pytest: В pytest, yield часто используется в фикстурах для разделения кода на часть, которая выполняется до тестов (секция “setup”), и часть, которая выполняется после тестов (секция “teardown”).

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

Что такое conftest.py файл? Зачем он нужен?

conftest.py — это специальный файл, используемый pytest, который содержит фикстуры и другие настройки, которые применяются к тестам на определенном уровне каталога. Это централизованное место для общих механизмов настройки тестов. Вот основные моменты, связанные с conftest.py:

  1. Область видимости: Фикстуры и конфигурации, определенные в conftest.py, автоматически доступны для всех тестовых файлов в том же каталоге и во всех подкаталогах.
  2. Порядок загрузки: Если есть несколько файлов conftest.py на разных уровнях в иерархии каталогов, pytest загрузит их все, начиная с самого верхнего уровня и заканчивая каталогом, в котором находятся тесты.
  3. Избегание импортов: Так как фикстуры в conftest.py автоматически доступны для всех тестов, вам не нужно импортировать их в каждом тестовом файле. Это делает код чище и упрощает масштабирование вашего тестового набора.

Веб-элемент в контексте Selenium — это представление элемента на веб-странице. Элементы на веб-странице могут включать в себя различные объекты, такие как кнопки, текстовые поля, изображения, гиперссылки, выпадающие списки и многие другие.

Какую информацию о веб элементе мы можем получить? https://www.selenium.dev/documentation/webdriver/elements/information/