Тестування -- це практика написання коду, який перевіряє, чи правильно працює ваш інший код. Більше того -- тести дають вам впевненість *змінювати* код. Коли ви рефакторите, виправляєте баг або додаєте функцію, тест-сьют одразу скаже, якщо щось зламалося деінде. Без тестів кожна зміна несе прихований ризик.
Найпростіший тест складається з трьох кроків:
1. Викликати вашу функцію з конкретним вхідним значенням
2. Зафіксувати результат
3. Перевірити, що результат дорівнює очікуваному
Якщо твердження істинне -- тест проходить. Якщо ні -- pytest покаже, що саме відрізнялось.
Ключове слово `assert` -- це вбудований механізм Python для цього: воно обчислює вираз і підіймає `AssertionError`, якщо результат хибний. У тесті ви пишете `assert result == expected` -- ось і весь фундамент. Наступна тема (*Assertions in Depth*) пояснює, як pytest драматично покращує вивід `assert` і охоплює патерни для порівняння float, списків, словників тощо.
**Чому pytest, а не unittest?**
У стандартній бібліотеці Python є `unittest`, але він багатослівний. Потрібно наслідуватися від `TestCase`, використовувати `self.assertEqual()` замість простого `assert` і загортати все у класи. pytest нічого цього не потребує:
```python
# unittest -- багато зайвого
import unittest
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
# pytest -- просто функція
def test_add():
assert add(2, 3) == 5
```
Крім синтаксису, повідомлення pytest при провалі набагато інформативніші -- він показує фактичні значення, що порівнювалися. І фікстури, parametrize та екосистема плагінів pytest незрівнянно кращі.
**Встановлення:**
```bash
pip install pytest
```
**Як працює виявлення тестів:**
pytest обходить директорію проекту і збирає тести за такими правилами іменування:
- Файли: `test_*.py` або `*_test.py`
- Функції на рівні модуля: починаються з `test_`
- Класи: починаються з `Test` (без методу `__init__`)
- Методи всередині класів `Test*`: починаються з `test_`
Все інше ігнорується. `helper.py`, `utils.py`, `main.py` -- не збираються. Функція `check_result()` -- не збирається. Тільки патерн `test_*` запускає збирання.
**Запуск тестів:**
```bash
pytest # запустити всі знайдені тести
pytest -v # докладний вивід: показати ім'я і результат кожного тесту
pytest -s # показувати вивід print() (не пригнічувати stdout)
pytest --tb=short # коротші трейсбеки при провалі
pytest --collect-only # показати, що буде запущено, без запуску
```
```bash
pytest # запустити всі тести
pytest -v # докладний вивід: показати ім'я кожного тесту
pytest -s # показувати вивід print() (не перехоплювати stdout)
pytest test_foo.py # запустити один файл
pytest -k "add" # тести, в назві яких є "add"
pytest --tb=short # коротші трейсбеки
pytest --tb=no # без трейсбеків (тільки кількість)
```
**Правила іменування, яким слідує pytest:**
- Файли: `test_*.py` або `*_test.py`
- Функції і методи: `test_*`
- Класи: `Test*` (без методу `__init__`)
**Що виводить pytest:**
```
collected 4 items
test_math_utils.py::test_add_positive_numbers PASSED
test_math_utils.py::test_add_negative PASSED
test_math_utils.py::test_clamp_within_range PASSED
test_math_utils.py::test_clamp_below_lower PASSED
4 passed in 0.05s
```
**Коли додавати `import pytest`:**
Простим тестам потрібні лише `assert` і власні імпорти -- `import pytest` не потрібен. Додавайте його при використанні pytest-специфічних можливостей: `pytest.approx` (порівняння float), `pytest.raises` (тестування винятків), `@pytest.fixture` або маркери на кшталт `@pytest.mark.parametrize`. Вони розглядаються в наступних темах.
Напишіть тест-функцію `test_add`, яка викликає `add(a, b)` принаймні з трьома різними парами вхідних значень і перевіряє правильний результат для кожної.
# math_utils.py
def add(a, b):
return a + b
# test_math_utils.py
from math_utils import add
def test_add():
# перевірте принаймні три пари вхідних значень
pass
Напишіть тест-функції для `is_even(n)`, які перевіряють, що вона повертає `True` для парних чисел і `False` для непарних. Напишіть принаймні дві тест-функції -- одну для парних входів, одну для непарних.
Наведений нижче тест містить навмисну помилку -- очікуване значення неправильне. Запустіть pytest і прочитайте вивід провалу, потім виправте очікуване значення, щоб тест пройшов.
def multiply(a, b):
return a * b
def test_multiply():
assert multiply(3, 4) == 11 # неправильне очікуване значення
assert multiply(0, 99) == 0
assert multiply(-2, 5) == -10
Напишіть три окремі тест-функції для `clamp(value, lo, hi)`: одну для значень у діапазоні, одну для значень нижче нижньої межі та одну для значень вище верхньої межі.
Напишіть тести для `greet(name)`, яка повертає `'Hello, {name}!'`. Перевірте, що повернуте значення починається з 'Hello', закінчується на '!' і містить передане ім'я.
def greet(name):
return f'Hello, {name}!'
def test_greet_alice():
result = greet('Alice')
assert result == 'Hello, Alice!'
assert result.startswith('Hello')
assert result.endswith('!')
assert 'Alice' in result
def test_greet_empty_name():
result = greet('')
assert result == 'Hello, !'
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 с
Щоб тренувати сліпий друк, не підглядайте на фізичну клавіатуру.