Приведи пример кейса, где использовал наследование
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример использования наследования в автоматизации тестирования
В автоматизации тестирования наследование — один из ключевых принципов ООП, который я активно применяю для создания гибкой и поддерживаемой тестовой инфраструктуры. Приведу реальный пример из проекта по тестированию веб-приложения электронной коммерции.
Контекст проекта
Мы разрабатывали фреймворк для тестирования интернет-магазина с разными типами пользователей: гостями, зарегистрированными пользователями и администраторами. Каждый тип пользователя имел общие действия (логин, навигация), но и уникальные сценарии.
Реализация через наследование
1. Базовый класс BaseTest
Создал абстрактный класс, содержащий общую логику для всех тестов:
import pytest
from selenium import webdriver
from pages.login_page import LoginPage
from config import Config
class BaseTest:
"""Базовый класс для всех тестовых классов"""
@pytest.fixture(autouse=True)
def setup(self, request):
"""Фикстура инициализации для каждого теста"""
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get(Config.BASE_URL)
# Логирование начала теста
test_name = request.node.name
print(f"\nЗапуск теста: {test_name}")
yield
# Закрытие браузера после теста
self.driver.quit()
print(f"Тест завершен: {test_name}")
def take_screenshot(self, name):
"""Общий метод для создания скриншотов"""
screenshot_path = f"screenshots/{name}.png"
self.driver.save_screenshot(screenshot_path)
return screenshot_path
def wait_for_element(self, locator, timeout=10):
"""Общий метод ожидания элемента"""
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
return WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located(locator)
)
2. Специализированные классы-наследники
Создал конкретные тестовые классы, которые наследуют общую функциональность:
class GuestTest(BaseTest):
"""Тесты для функциональности гостя"""
def test_browse_products(self):
"""Гость может просматривать товары"""
home_page = HomePage(self.driver)
products = home_page.get_product_list()
assert len(products) > 0, "Нет товаров для отображения"
def test_add_to_cart_requires_login(self):
"""Гость должен авторизоваться для добавления в корзину"""
product_page = ProductPage(self.driver)
product_page.add_to_cart()
assert "login" in self.driver.current_url, "Не перенаправило на логин"
class RegisteredUserTest(BaseTest):
"""Тесты для зарегистрированных пользователей"""
@pytest.fixture(autouse=True)
def user_login(self):
"""Дополнительная фикстура для логина пользователя"""
login_page = LoginPage(self.driver)
login_page.login(Config.USER_EMAIL, Config.USER_PASSWORD)
yield
def test_add_to_cart(self):
"""Пользователь может добавлять товары в корзину"""
product_page = ProductPage(self.driver)
product_page.add_to_cart()
assert product_page.is_item_in_cart(), "Товар не добавлен в корзину"
def test_view_order_history(self):
"""Пользователь может просматривать историю заказов"""
account_page = AccountPage(self.driver)
orders = account_page.get_order_history()
assert orders is not None, "История заказов недоступна"
class AdminTest(RegisteredUserTest):
"""Тесты для администратора (наследует от RegisteredUserTest)"""
@pytest.fixture(autouse=True)
def admin_login(self):
"""Переопределение фикстуры для логина администратора"""
login_page = LoginPage(self.driver)
login_page.login(Config.ADMIN_EMAIL, Config.ADMIN_PASSWORD)
yield
def test_manage_products(self):
"""Админ может управлять товарами"""
admin_page = AdminPage(self.driver)
admin_page.add_new_product("Новый товар", 99.99)
assert admin_page.is_product_created("Новый товар"), "Товар не создан"
def test_view_sales_report(self):
"""Админ может просматривать отчеты"""
report_page = ReportPage(self.driver)
report = report_page.generate_sales_report()
assert report.total_sales > 0, "Некорректный отчет о продажах"
Преимущества такого подхода
1. Устранение дублирования кода
- Общие методы (
take_screenshot,wait_for_element) определены один раз в базовом классе - Фикстура
setupавтоматически применяется ко всем тестам
2. Гибкость и расширяемость
- Можно легко добавлять новые типы тестов
- Переопределение методов позволяет адаптировать общую логику под конкретные нужды
- Иерархия наследования:
AdminTest → RegisteredUserTest → BaseTest
3. Упрощение поддержки
- Изменения в общей логике вносятся в одном месте
- Четкая структура классов улучшает читаемость кода
- Легко находить и исправлять дефекты в общей функциональности
4. Повторное использование кода
- Фикстуры и вспомогательные методы доступны во всех наследниках
- Можно создавать промежуточные классы для разных категорий тестов
Дополнительный пример: Page Object с наследованием
class BasePage:
"""Базовый класс для всех Page Object"""
def __init__(self, driver):
self.driver = driver
def find_element(self, locator):
return self.wait_for_element(locator)
def is_displayed(self, locator):
try:
return self.find_element(locator).is_displayed()
except:
return False
class CheckoutPage(BasePage):
"""Страница оформления заказа"""
def __init__(self, driver):
super().__init__(driver)
self.shipping_section = ShippingSection(driver)
self.payment_section = PaymentSection(driver)
def complete_purchase(self):
self.shipping_section.select_shipping()
self.payment_section.enter_payment_details()
self.click_confirm_button()
Вывод
Наследование в автоматизации тестирования позволяет создавать структурированные, легко поддерживаемые тестовые фреймворки. В описанном примере оно помогло:
- Организовать код в логическую иерархию
- Минимизировать дублирование
- Обеспечить легкую расширяемость фреймворка
- Упростить onboarding новых QA-инженеров благодаря четкой архитектуре
Этот подход особенно ценен в долгосрочных проектах, где требования постоянно меняются, а тестовая кодовая база растет.