← Назад к вопросам

Приведи пример кейса, где использовал наследование

2.0 Middle🔥 121 комментариев
#Другое

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример использования наследования в автоматизации тестирования

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

Контекст проекта

Мы разрабатывали фреймворк для тестирования интернет-магазина с разными типами пользователей: гостями, зарегистрированными пользователями и администраторами. Каждый тип пользователя имел общие действия (логин, навигация), но и уникальные сценарии.

Реализация через наследование

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-инженеров благодаря четкой архитектуре

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