Що ви опануєте
Ви навчитеся розділяти відповідальності, обирати рівень перевірки й організовувати спільні зміни так, щоб інша людина могла їх зрозуміти та відтворити. Розглянемо правила бронювання як окрему частину сервісу. Зміна інтерфейсу чи сховища має залишати ці правила зрозумілими й перевірюваними.
Відповідальності та залежності
Модуль — частина програми з визначеним призначенням та інтерфейсом. Зв’язність описує, наскільки його частини працюють на спільну мету. Зчеплення характеризує залежності між модулями. Якщо функція одночасно читає консоль, перевіряє місткість і пише файл, зміна формату введення зачіпає правило бронювання. Розділення дозволяє перевіряти правило на простих даних.
Інтерфейс визначає доступні операції та їх контракт. Реалізація забезпечує конкретну поведінку. Сховище може надавати save_booking, а сервіс працювати з цією операцією без знання формату файлу. Межі обирають за реальною відповідальністю: надмірна кількість дрібних шарів у простій програмі збільшує витрати на читання.
Чиста логіка та побічні ефекти
Побічний ефект — зміна зовнішнього стану: запис у файл, мережевий запит, зміна глобального списку. Чиста функція повертає результат за переданими даними без таких змін. Правило доступності легко зробити чистим, а збереження — окремою операцією. Така організація зменшує кількість умов середовища, потрібних для перевірки.
def remaining(capacity: int, booked: int) -> int:
if capacity < 0 or booked < 0 or booked > capacity:
raise ValueError("Некоректний стан місткості")
return capacity - booked
# Логіка перевіряється без файлів або мережі.
assert remaining(3, 1) == 2
assert remaining(3, 3) == 0
Функція має явні параметри й повертає число. Перевірка booked > capacity виявляє порушення інваріанта, яке могло виникнути раніше. Вивід повідомлення можна реалізувати окремо: print(f"Вільних місць: {remaining(3, 1)}"). Це дозволяє використовувати той самий розрахунок у консольному, вебовому або мобільному інтерфейсі.
Рівні перевірки
Модульний тест перевіряє невелику одиницю поведінки. Інтеграційний тест перевіряє взаємодію частин: наприклад, сервіс і базу даних. Системний тест проходить сценарій готової системи. Приймальна перевірка встановлює відповідність потребі й погодженим критеріям. Рівень обирають за ризиком, який потрібно перевірити.
Тест чистої функції не підтверджує, що база даних зберегла запис. Успішний сценарій у браузері не пояснює всі граничні стани розрахунку. Для основних правил потрібні короткі точні тести, а для критичних взаємодій — перевірки на відповідному рівні. Необхідно також перевіряти, що тест справді виявляє помилку: навмисна зміна умови на границі має спричинити відмову.
Структура тесту
Тест містить підготовку даних, дію й перевірку результату. Кожен приклад має назву, яка описує поведінку. Очікуване значення визначають із вимоги, щоб тест не повторював помилковий алгоритм реалізації. Для винятку перевіряють, що він виникає за конкретного некоректного входу.
import unittest
class RemainingTests(unittest.TestCase):
def test_full_consultation_has_zero_places(self):
self.assertEqual(remaining(3, 3), 0)
def test_overbooked_state_is_rejected(self):
with self.assertRaises(ValueError):
remaining(3, 4)
# У файлі з попередньою функцією запускати: python -m unittest файл
TestCase надає перевірки й механізм запуску. assertEqual порівнює фактичний і очікуваний результати. Контекст assertRaises завершується помилкою тесту, якщо потрібний виняток не виник. Під час налагодження читають перший змістовний збій і відтворюють його мінімальним набором даних.
Контроль версій
Git commit фіксує узгоджений стан змін із поясненням. Гілка дає окрему лінію роботи. Merge об’єднує історії; конфлікт виникає, коли автоматичне узгодження змін неможливе. Після вирішення конфлікту потрібно повторити релевантні перевірки, оскільки синтаксично правильне об’єднання може порушити правило.
Невеликий логічний commit легше переглядати. Повідомлення описує зміну поведінки: «відхилити бронювання заповненої консультації». Згенеровані файли, залежності та секрети зберігають за правилами репозиторію; токени доступу не мають потрапляти в історію. Перед commit переглядають diff і список файлів, щоб випадкові локальні артефакти не змішалися з роботою.
Review і автоматизація
Code review — спільний аналіз зміни перед інтеграцією. Перевіряють відповідність вимозі, зрозумілість, помилки та достатність тестів. Коментар має вказувати конкретний ризик і приклад. Зауваження про особистий стиль відокремлюють від порушень узгодженого контракту. Автор пояснює причину рішення й виправляє підтверджені проблеми.
Continuous Integration регулярно збирає й перевіряє інтегровані зміни. Зелений результат означає проходження налаштованих перевірок у конкретному середовищі. Він не доводить відсутність усіх помилок і не замінює оцінку покриття ризиків. Зміна конфігурації тестів теж має бути предметом review, щоб випадково не вимкнути важливий захист.
Типові помилки та професійна практика
Поширена помилка — додавати залежність від часу або випадковості без можливості керувати нею в тесті. Інша — перевіряти тільки позитивний сценарій і залишати порожній вхід без контракту. Великі commits із кількома незалежними змінами ускладнюють пошук причини відмови. Робіть перевірки відтворюваними та пояснюйте, які ризики вони покривають.
Практичний аналіз
Для скасування консультації визначте модульну перевірку правила доступу, інтеграційну перевірку видалення запису та системний сценарій повідомлення користувача. Поясніть, які помилки не помітить кожна перевірка окремо. Складіть опис логічного commit, який реалізує лише один узгоджений результат.
Перевірка зміни в команді
Уявіть зміну правила місткості: раніше консультація мала лише один слот, тепер дозволено кілька місць. Перед редагуванням визначте залежні вимоги, модель даних, повідомлення й тести. Невелика чиста функція розрахунку залишку ізолює предметне правило, але її правильність ще потрібно пов’язати з узгодженим записом у сховище.
Модульний тест перевіряє функцію на конкретному вході. Інтеграційний тест перевіряє взаємодію, наприклад створення запису й оновлення доступності. Системний сценарій проходить шлях користувача. Розподіляйте перевірки за ризиком: арифметику зручно перевіряти багатьма малими прикладами, а доступ до останнього місця потребує перевірки конкуренції на рівні інтеграції.
Рецензування коду має зрозумілу мету: чи зміна відповідає вимозі, чи можна пояснити інваріант, чи нова залежність виправдана, чи перевірено відмову. Коментар повинен називати конкретний ризик і бажаний результат. Наприклад, «при нульовому залишку операція має завершитися без створення запису; додай перевірку цього стану» дає автору дію та критерій.
Після об’єднання зміни CI відтворює перевірки в узгодженому середовищі. Зелений результат означає проходження саме налаштованих перевірок. Для нової вимоги спершу перевірте, чи вони охоплюють потрібну поведінку. Зафіксуйте перевірені сценарії в описі зміни та обмеження, які залишилися поза цим набором. Це дозволяє команді оцінити ризик випуску за конкретними свідченнями.
Схема процесу
Визначаємо контракт поведінки.
Самоперевірка
Як обґрунтувати відповідь своїми словами?
Підсумок
Зрозумілі межі відповідальності роблять зміни локальнішими й перевірки точнішими. Різні рівні тестів покривають різні ризики. Контроль версій, review та CI забезпечують відтворювану командну роботу за умови, що перевірки пов’язані з вимогами.