Оператор `assert` в Python сам по себе минималистичен: если выражение ложно, он выбрасывает `AssertionError` без какой-либо полезной информации:
```python
# обычный assert Python
assert result == expected
# -> AssertionError (только исключение, ничего больше)
```
pytest решает эту проблему с помощью **переписывания утверждений**. Когда pytest импортирует ваш тестовый файл, он преобразует байткод так, чтобы каждый `assert` захватывал обе стороны сравнения до его вычисления. При падении вы видите точно, что различалось:
```
# сравнение списков:
AssertionError: assert [1, 2, 3] == [1, 2, 4]
At index 2 diff: 3 != 4
# сравнение словарей:
AssertionError: assert {'name': 'Alice', 'age': 31} == {'name': 'Alice', 'age': 30}
Differing items:
{'age': 31} != {'age': 30}
# сравнение строк:
AssertionError: assert 'hello earth' == 'hello world'
At position 6 diff: 'e' != 'w'
```
Это делает падения самодиагностирующимися. Вы видите *что именно* различалось, а не просто *что* что-то различалось.
**`==` против `is`**
`==` проверяет *равенство* (одинаковое значение). `is` проверяет *идентичность* (один и тот же объект в памяти). Используйте `is` для булевых значений и `None`:
```python
assert result is True # result является булевым True
assert result == True # тоже работает, но 1 == True тоже True (менее строго)
assert result is not None # понятно и идиоматично
```
Для чисел, строк и коллекций всегда используйте `==`. Проверка `is` для строк и целых чисел может давать неожиданные результаты из-за интернирования объектов в Python.
**Отрицание:**
```python
assert x != y # не равно
assert x not in lst # не в коллекции
assert not condition # общее отрицание
```
**Пользовательские сообщения при падении:**
Добавьте сообщение после утверждения -- pytest покажет его вместе с самим утверждением:
```python
assert score >= 50, f"Expected score >= 50, got {score}"
# -> AssertionError: Expected score >= 50, got 42
# assert 42 >= 50
```
**Сравнение чисел с плавающей точкой:**
`0.1 + 0.2` в Python не равно точно `0.3` из-за двоичного представления с плавающей точкой. Используйте `pytest.approx`:
```python
import pytest
assert 0.1 + 0.2 == pytest.approx(0.3) # по умолчанию: относительная погрешность 1e-6
assert result == pytest.approx(1.5, rel=1e-3) # с точностью 0.1%
assert result == pytest.approx(0.0, abs=1e-9) # абсолютная погрешность (лучше около нуля)
```
Используйте `rel` (относительная), когда величина большая; используйте `abs` (абсолютная), когда ожидаемое значение равно или близко к нулю (деление на ноль в относительной проверке было бы проблемой).
```python
# Равенство / неравенство
assert x == y
assert x != y
# Порядок
assert x > y
assert x >= y
assert x < y
assert x <= y
# Вхождение
assert item in collection
assert item not in collection
# Тип
assert isinstance(obj, SomeClass) # принимает подклассы
assert type(obj) is int # только точный тип
# Истинность
assert value # истинное (ненулевое, непустое, не None)
assert not value # ложное
# Числа с плавающей точкой
assert x == pytest.approx(y) # относительная погрешность по умолчанию 1e-6
assert x == pytest.approx(y, rel=1e-3) # погрешность 0.1%
assert x == pytest.approx(y, abs=0.01) # абсолютная погрешность +-0.01
# Строки
assert s.startswith('prefix')
assert s.endswith('suffix')
assert 'substring' in s
# Пользовательское сообщение при падении
assert condition, f"Описательное сообщение: получено {value}"
```
Напишите тесты для `to_celsius(f)`, которая конвертирует градусы Фаренгейта в Цельсий по формуле `(f - 32) * 5 / 9`. Проверьте результат для как минимум трёх значений: 32°F (0°C), 212°F (100°C) и 98.6°F (37°C). Используйте `pytest.approx` для сравнения чисел с плавающей точкой.
Реализуйте `circle_area(r)`, которая возвращает `pi * r^2`, используя `math.pi`. Напишите тесты, проверяющие, что площадь при `r=3` приблизительно равна `28.274` (с погрешностью 0.1%), при `r=1` -- приблизительно `3.14159`. Также протестируйте `r=0`.
import math
import pytest
def circle_area(r):
pass # реализуйте здесь
def test_circle_area():
pass
Напишите `top_scores(scores, n)`, которая возвращает топ `n` очков из списка, отсортированных по убыванию. Напишите тесты, проверяющие, что возвращаемый тип -- список, его длина равна `n`, и конкретные значения присутствуют или отсутствуют.
def top_scores(scores, n):
pass # реализуйте здесь
def test_top_scores():
pass
Решение
def top_scores(scores, n):
return sorted(scores, reverse=True)[:n]
def test_top_scores_returns_list():
result = top_scores([5, 1, 8, 3, 9], 3)
assert isinstance(result, list)
def test_top_scores_length():
result = top_scores([5, 1, 8, 3, 9], 3)
assert len(result) == 3
def test_top_scores_correct_values():
result = top_scores([5, 1, 8, 3, 9], 3)
assert 9 in result
assert 8 in result
assert 5 in result
assert 1 not in result
Напишите `parse_user(s)`, которая разбирает строку вроде `'name:Alice,age:30'` в словарь. Напишите тесты, проверяющие, что конкретные ключи существуют, значения правильные, а лишние ключи отсутствуют.
def parse_user(s):
result = {}
for pair in s.split(','):
key, value = pair.split(':')
result[key.strip()] = value.strip()
return result
def test_parse_user_name():
user = parse_user('name:Alice,age:30')
assert 'name' in user
assert user['name'] == 'Alice'
def test_parse_user_age():
user = parse_user('name:Alice,age:30')
assert 'age' in user
assert user['age'] == '30'
def test_parse_user_no_extra_keys():
user = parse_user('name:Alice,age:30')
assert 'email' not in user
assert len(user) == 2
Напишите `format_greeting(name, title)`, которая возвращает `'Dear {title}. {name},'`. Напишите тесты, проверяющие, что результат начинается с 'Dear', заканчивается на ',', содержит имя и не имеет двойных пробелов.
def format_greeting(name, title):
pass # реализуйте здесь
def test_format_greeting():
pass
Решение
def format_greeting(name, title):
return f'Dear {title}. {name},'
def test_greeting_starts_with_dear():
result = format_greeting('Smith', 'Dr')
assert result.startswith('Dear')
def test_greeting_ends_with_comma():
result = format_greeting('Smith', 'Dr')
assert result.endswith(',')
def test_greeting_contains_name():
result = format_greeting('Smith', 'Dr')
assert 'Smith' in result
def test_greeting_no_double_spaces():
result = format_greeting('Smith', 'Dr')
assert ' ' not in result
No split tab
Настройки cookies
Мы используем необходимые cookies для работы сайта. С вашего разрешения мы также можем сохранять настройки сайта и использовать аналитические и рекламные cookies, чтобы понимать использование сайта и поддерживать развитие проекта.
* Вы всегда можете изменить свой выбор в настройках сайта.
Выберите категории cookies
Настройки аналитики
Можно отключить аналитику использования платформы. Также можно отправить в Google Analytics запрос на удаление данных об использовании этого сайта, связанных с этим браузером.
Учебный workspace
Учитесь, читая, запуская код и решая задачи.
Практикуйте программирование с пояснениями тем, упражнениями, инструментами browser IDE, проверкой regex и тренировкой печати кода в одном workspace.
Открывайте инструменты во вкладках.Упражнения, IDE-инструменты и тренажеры остаются доступными как вкладки сайта.
Переключайтесь без потери контекста.Переходите между пояснениями, кодом и утилитами, сохраняя свое место.
Используйте sidebar как карту.Левые панели содержат навигацию, настройки, файлы, libraries и управление инструментами.
PythonJavaScriptSQLite
Одна IDE, три практичных режима
Python в браузере.Запускайте небольшие скрипты, пробуйте библиотеки и тренируйте API-запросы без установки.
JavaScript для быстрых экспериментов.Проверяйте код для браузера и сравнивайте идеи рядом с учебными материалами.
SQLite для практики с данными.Открывайте обозреватель базы данных, изучайте таблицы, пишите запросы и учитесь SQL локально.
ТемаIDE
Работайте рядом в split tabs
Держите инструкции перед глазами.Откройте упражнение или справочную страницу рядом с IDE, вместо постоянных переключений.
Сравнивайте инструменты во время обучения.Размещайте проверки regex, пояснения и эксперименты с кодом рядом, когда это нужно для задачи.
Закройте split, когда закончите.Workspace вернётся к одной сфокусированной вкладке, а открытые вкладки сайта останутся доступны.
Тренажер слепой печати кода
Или просто текста
Тренажер рассчитан на физическую клавиатуру.Откройте этот раздел на ноутбуке или компьютере с широким экраном. На телефоне тренировка слепой печати не будет корректной.
Скорость: 0 зн/мин
0 слов/мин
Лучшая скорость (60с): 0 зн/мин
0 слов/мин
Ошибки: 0
Общее время: 0.0 с
Для активации режима слепого набора не подсматривайте на физическую клавиатуру.