Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Тестируем классы и ошибки
testing_classes_and_errors

Тестируем классы и ошибки

Тестирование методов классов, pytest.raises для исключений, проверка текста ошибки

До этого момента мы тестировали только функции. Но в реальных проектах вы будете работать с классами и обрабатывать ошибки.

Цель: научиться тестировать методы классов и проверять, что код правильно выбрасывает исключения.

Тестирование методов классов

Создайте класс для тестирования

# src/user.py class User: def __init__(self, name, age): self.name = name self.age = age def greet(self): """Возвращает приветствие""" return f"Hello, I'm {self.name}!" def is_adult(self): """Проверяет совершеннолетие""" return self.age >= 18 def celebrate_birthday(self): """Увеличивает возраст на 1""" self.age += 1 return self.age

Напишите тесты

# tests/test_user.py from src.user import User def test_user_creation(): """Тест создания пользователя""" user = User("Alice", 25) assert user.name == "Alice" assert user.age == 25 def test_greet(): """Тест метода приветствия""" user = User("Bob", 30) greeting = user.greet() assert greeting == "Hello, I'm Bob!" def test_is_adult_true(): """Совершеннолетний пользователь""" user = User("Alice", 25) assert user.is_adult() == True def test_is_adult_false(): """Несовершеннолетний пользователь""" user = User("Charlie", 16) assert user.is_adult() == False def test_celebrate_birthday(): """Тест дня рождения""" user = User("Alice", 25) new_age = user.celebrate_birthday() assert new_age == 26 assert user.age == 26 # Проверяем что state изменился

Запускаем:

pytest tests/test_user.py -v

Результат:

test_user_creation PASSED                                            [ 20%]
test_greet PASSED                                                    [ 40%]
test_is_adult_true PASSED                                           [ 60%]
test_is_adult_false PASSED                                           [ 80%]
test_celebrate_birthday PASSED                                      [100%]

============================= 5 passed in 0.02s =============================

✅ Все методы класса протестированы!

Тестирование исключений: pytest.raises

Почему нужно тестировать ошибки?

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

Пример: деление на ноль должно выбросить ValueError, а не вернуть странное значение.

Создайте код с валидацией

# src/validator.py def validate_email(email): """Проверяет email""" if "@" not in email: raise ValueError("Email must contain @") if "." not in email: raise ValueError("Email must contain domain") return True def validate_age(age): """Проверяет возраст""" if age < 0: raise ValueError("Age cannot be negative") if age > 150: raise ValueError("Age too high") return True def divide(a, b): """Делит a на b""" if b == 0: raise ZeroDivisionError("Cannot divide by zero") return a / b

Тестируем исключения с pytest.raises

# tests/test_validator.py import pytest from src.validator import validate_email, validate_age, divide def test_validate_email_missing_at(): """Email без @ должен выбросить ошибку""" with pytest.raises(ValueError): validate_email("invalid.email.com") def test_validate_email_missing_domain(): """Email без домена должен выбросить ошибку""" with pytest.raises(ValueError): validate_email("test@") def test_validate_age_negative(): """Отрицательный возраст должен выбросить ошибку""" with pytest.raises(ValueError): validate_age(-5) def test_validate_age_too_high(): """Слишком большой возраст должен выбросить ошибку""" with pytest.raises(ValueError): validate_age(200) def test_divide_by_zero(): """Деление на ноль должно выбросить ошибку""" with pytest.raises(ZeroDivisionError): divide(10, 0)

Что делает pytest.raises:

  • ✅ Тест ПРОЙДЁТ, если код выбросил ожидаемое исключение
  • ❌ Тест ПРОВАЛИТСЯ, если исключение НЕ было выброшено
  • ❌ Тест ПРОВАЛИТСЯ, если выброшено ДРУГОЕ исключение

Проверка сообщения об ошибке

Можно проверить не только ТИП исключения, но и ТЕКСТ ошибки:

def test_validate_email_with_message(): """Проверяем и тип, и текст ошибки""" with pytest.raises(ValueError) as exc_info: validate_email("invalid.com") # Проверяем текст ошибки assert str(exc_info.value) == "Email must contain @" def test_divide_by_zero_message(): """Проверяем сообщение при делении на ноль""" with pytest.raises(ZeroDivisionError) as exc_info: divide(10, 0) assert "Cannot divide by zero" in str(exc_info.value)

Зачем проверять сообщение?

  • Пользователи видят это сообщение при ошибке
  • Хорошее сообщение помогает понять ЧТО пошло не так
  • Тест защищает от случайного изменения текста ошибки

Практический пример: BankAccount

Создайте класс с валидацией

# src/bank_account.py class BankAccount: def __init__(self, balance=0): if balance < 0: raise ValueError("Initial balance cannot be negative") self.balance = balance def deposit(self, amount): """Пополнить счёт""" if amount <= 0: raise ValueError("Deposit amount must be positive") self.balance += amount return self.balance def withdraw(self, amount): """Снять деньги""" if amount <= 0: raise ValueError("Withdrawal amount must be positive") if amount > self.balance: raise ValueError("Insufficient funds") self.balance -= amount return self.balance

Напишите полный набор тестов

# tests/test_bank_account.py import pytest from src.bank_account import BankAccount # Тесты счастливого пути def test_create_account(): """Создание счёта с балансом""" account = BankAccount(100) assert account.balance == 100 def test_deposit(): """Пополнение счёта""" account = BankAccount(100) new_balance = account.deposit(50) assert new_balance == 150 assert account.balance == 150 def test_withdraw(): """Снятие денег""" account = BankAccount(100) new_balance = account.withdraw(30) assert new_balance == 70 assert account.balance == 70 # Тесты ошибок def test_negative_initial_balance(): """Нельзя создать счёт с отрицательным балансом""" with pytest.raises(ValueError) as exc_info: BankAccount(-100) assert "cannot be negative" in str(exc_info.value) def test_deposit_negative(): """Нельзя пополнить на отрицательную сумму""" account = BankAccount(100) with pytest.raises(ValueError): account.deposit(-50) def test_withdraw_more_than_balance(): """Нельзя снять больше чем есть на счёте""" account = BankAccount(100) with pytest.raises(ValueError) as exc_info: account.withdraw(200) assert "Insufficient funds" in str(exc_info.value)

Запускаем:

pytest tests/test_bank_account.py -v
============================= 7 passed in 0.02s =============================

Типичные ошибки

Ошибка #1: забыли использовать pytest.raises

# ❌ ПЛОХО — тест провалится, потому что исключение не поймано def test_divide_by_zero_bad(): divide(10, 0) # Это выбросит ошибку и тест упадёт! # ✅ ХОРОШО def test_divide_by_zero_good(): with pytest.raises(ZeroDivisionError): divide(10, 0)

Ошибка #2: неправильный тип исключения

# ❌ ПЛОХО — ожидаем ValueError, но выбрасывается ZeroDivisionError def test_wrong_exception(): with pytest.raises(ValueError): # Ожидаем ValueError divide(10, 0) # Но выбрасывается ZeroDivisionError! # Тест провалится: "DID NOT RAISE ValueError"

Ошибка #3: код не выбрасывает исключение

# ❌ ПЛОХО — забыли raise в коде def bad_validate_age(age): if age < 0: print("Age cannot be negative") # Только print! # Забыли raise! return True def test_bad_validation(): with pytest.raises(ValueError): bad_validate_age(-5) # Исключение НЕ выбросится! # Тест провалится: "DID NOT RAISE ValueError"

Что вы изучили

  • Тестирование методов классов — создание объектов в тестах
  • pytest.raises — проверка исключений
  • Проверка error messages — через exc_info.value
  • Тестирование edge cases — негативные сценарии (ошибки)
  • Счастливый путь VS ошибки — оба важны!

Устранение неисправностей

Проверьте свои знания

Вопросы ещё не добавлены

Вопросы для этой подтемы ещё не добавлены.

Далее: AAA-паттерн: тесты, которые ловят баги