# Домашнє завдання · Тестування з pytest

> Лекція: [lecture.html](lecture.html) · Практика: [practice.ipynb](practice.ipynb) · Тест: [quiz.html](quiz.html)

Усі три рівні працюють з тим самим кошиком покупок, що й лекція. Якщо `pytest` у тебе
не встановлений — постав його у [віртуальному середовищі](../17-venv-pip/lecture.html):

```bash
python3 -m venv .venv
source .venv/bin/activate        # у Windows: .venv\Scripts\activate
python3 -m pip install pytest
```

Якщо поставити не вдається — не біда: у практиці ми написали власну функцію
`перевірити()`, і всі три завдання можна зробити з нею. Змінюється лише спосіб
запуску, а не суть.

---

## 🟢 Рівень 1 — База

Створи теку проєкту з двома файлами.

У `кошик.py` напиши функцію `разом_за_чек(позиції)`, яка приймає список пар
`(ціна, кількість)` і повертає загальну суму до сплати з урахуванням знижки
(правила ті самі: 0% до 200, 5% від 200, 10% від 500 — знижка рахується від
**усього чека**, а не від позиції).

У `test_кошик.py` напиши щонайменше **пʼять** тестів: порожній чек, один товар,
кілька товарів без знижки, чек із 5% знижкою, чек із 10% знижкою.

**Зроблено, якщо:** команда `python3 -m pytest -q` у теці проєкту друкує
`5 passed` (або більше), а кожен тест має імʼя, з якого зрозуміло, що саме він
перевіряє, без відкривання файлу.

---

## 🟡 Рівень 2 — Плюс

Візьми свою `разом_за_чек` і **зіпсуй** її навмисно: заміни в одній з умов `<` на `<=`.
Перевір: чи знайшов це твій набір із рівня 1?

Якщо ні (а швидше за все — ні), додай межові тести так, щоб набір ловив помилку на
**обох** порогах. Оформи їх одним параметризованим тестом:

```python
@pytest.mark.parametrize("сума_чека, очікувана_знижка", [
    # заповни таблицю сам
])
def test_знижка_на_межах(сума_чека, очікувана_знижка):
    ...
```

Потім полагодь функцію й переконайся, що набір знову зелений.

**Зроблено, якщо:** у тебе є три записані числа — скільки тестів було червоних
**до** додавання меж (очікуємо 0), скільки **після** (очікуємо щонайменше 2) і
скільки після полагодження (очікуємо 0). Плюс один параметризований тест
замість чотирьох окремих.

---

## 🔴 Рівень 3 — Виклик

Доведи на власному коді, що **покриття не гарантує якості**.

1. Напиши тест `test_нічого_не_перевіряє`, який викликає всі функції твого модуля
   й не містить жодного `assert`.
2. Виміряй покриття: `python3 -m pip install pytest-cov`, далі
   `python3 -m pytest --cov=кошик -q`. Запиши відсоток.
3. Зламай `кошик.py` як завгодно грубо — хоч `return 0` у кожній функції.
4. Прожени **тільки** цей тест ще раз і подивись на результат та на покриття.

**Зроблено, якщо:** ти можеш показати два прогони, де той самий тест зелений і
покриття однакове — на робочому і на явно зламаному модулі, — і пояснити у два
речення, у чому різниця між «рядок виконано» і «результат перевірено».

Якщо `pytest-cov` поставити не виходить, зроби завдання без вимірювання покриття:
достатньо показати, що тест без `assert` зелений на будь-якому коді, і пояснити чому.

---

## Підказки

- **Не пиши тест «на всяк випадок».** Перед кожним тестом спитай себе: яку саме
  поломку він спіймає? Якщо відповіді немає — тест не потрібен.
- **Межа — це два сусідні числа.** Перевіряй не тільки 200, а й 199: разом вони
  доводять, що поріг стоїть саме там, де треба, а не зсунутий на одиницю.
- **Спершу подивись на червоне.** Зламай функцію навмисно й переконайся, що твій
  тест це помітив. Тест, який жодного разу не падав, може не перевіряти нічого.
- **Порожній список — теж випадок.** `разом_за_чек([])` має повернути щось розумне
  (найімовірніше `0.0`), і це варто зафіксувати тестом, а не лишати на здогад.
- **Числа з рухомою крапкою.** Якщо тест несподівано червоний, а числа на вигляд
  однакові, — придивись до розрядів: `19.99 * 7` не дорівнює `139.93` без
  `round`. Про це була [тема 04](../04-numbers/lecture.html).
