TDD в PHP, ч. 3: що і як варто покривати тестами

5 хв. читання

Це остання стаття з серії статей про TDD в PHP. Сьогодні ми більш детально поговоримо про те, що варто покривати тестами і як автоматично побудувати звіти про тестування, щоб не пропустити нічого важливого.

Що варто покривати тестами?

1. Тестувати потрібно бізнес-логіку, а не мову програмування

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

Зазвичай Гетери й Cетери тестувати не потрібно, якщо в них немає додаткової логіки.

2. Максимально уникати дублювання коду

\ Правило стосується не лише тестів, а й загалом розробки. Код, що дублюється, важче і дорожче підтримувати. До того ж, це збільшує ризик допуститися помилки. \ Одним з інструментів уникнення дублювання коду в юніт-тестах є анотації @before, @after, які дозволяють реалізувати підготовку об'єкта один раз для всіх тестових методів.

3. Одночасно можна тестувати лише одну річ, один логічний вузол

\ Тести повинні бути маленькими, ізольованими, з можливістю повторного відтворення за однакових умов. На них не мають впливати конфігураційні дані, реальна БД, зовнішні ресурси, інші об'єкти тощо. Юніт не має залежати від зовнішніх факторів.

4. Один клас тест-кейсу для одного класу бізнес-логіки

\ Це теж полегшує підтримку тестів в майбутньому, інакше доведеться шукати, в якому ж класі тест-кейсів лежить потрібний тестовий метод.

5. Кілька тестів для одного методу

\ В будь-якому методі є один або кілька логічних вузлів. Кожен з них має бути покритий тестами. Під логічними вузлами мається на увазі всі розгалуження, цикли тощо. Все те, що реалізовує алгоритм. \ Забагато тестів на один метод — теж погано, у всьому варто знати міру. В середньому приблизно йде 3-5 тестів на один метод.

Тести потрібно писати доти, доки страх не перетвориться в нудьгу - @Simon Allardice

6. Тести повинні бути унітарними

\ Хороша практика — уникати залежних між собою тестів. У протилежному випадку використання, @after стає неоднозначним. Тому доведеться або писати ізольовані тести з використанням @before, @after, або дублювати код підготовки й завершення тесту + у разі виникнення помилки, аналізувати всі пов'язані між собою тести.

В тесті потрібно мінімізувати кількість точок провалу тесту - це полегшить роботу з пошуком проблеми

7. Тести мають перевіряти лише цільовий клас

\ Як правило, тести не повинні взаємодіяти з реальною БД, файловою системою чи будь-якою іншою зовнішньою системою. \ У випадках, коли метод взаємодіє з іншими об'єктами, доцільно використовувати Dummy об'єкти — вони дозволяють наперед визначити масив даних, що повертається замість відповіді методу стороннього об'єкту.

Випадки, у яких варто використовувати Dummy:

  • Коли реальні об'єкти ще не написані,
  • Якщо для виконання тесту потрібна взаємодія користувача з інтерфейсом. В такому випадку ми емулюємо те, що має повернути інтерфейс,
  • Повільна або складна підготовка тесту (@before),
  • Взаємодія із зовнішніми ресурсами/об'єктами.

Для реалізації об'єктів-заглушок існує кілька підходів:

  • Mock об'єкти (PHPUnit\\Framework\\TestCase::getMock()), які дозволяють імітувати об'єкт класу і повернути потрібні для тесту дані,
  • Тестові Шпигуни — їх використання допускається лише у тих випадках, де не можна використати Mock об'єкти,
  • RunKit пісочниця.

Тема досить велика і заслуговує окремої статті.

Аналіз покриття коду

Рівень покриття коду тестами завжди викликав дискусію: покривати код на всі 100% чи ні. Хтось говорить про те, що є сенс покривати максимум 80% коду. Колись слухав доповідь СТО однієї глобальної компанії, він говорив про те, що вони прагнуть покрити тестами 50% коду... \ Особисто мені імпонує думка, що код потрібно покривати рівно до тих пір, доки в цьому є необхідність. Якщо код покритий на 30% тестами, але при цьому присутня впевненість, що цього достатньо, щоб забезпечити надійність системи, то «навіщо платити більше!?».

Налаштування звітів PHPUnit Code Coverage

За основу слід взяти налаштування, які описані в другій статті серії. \ Щоб згенерувати звіт, потрібно виконати наступні дії:

  1. Створити файл phpunit.xml (документація),
  2. Зайти в налаштування PHPStorm і вказати шлях до створеного файлу (https://prnt.sc/jhfsq9),
  3. Пересвідчитися, що на локальному сервері встановлений/включений xDebug, без нього нічого не працюватиме.

Генерація звіту

Для того, щоб згенерувати звіт, для прикладу з першої статті, я створив файл phpunit.xml з наступним вмістом (файлова структура):

<phpunit bootstrap="./userTest.php"
		 colors="true"
		 stopOnFailure="true">

	<testsuite name="Main Test Suite">
		<directory>./classes/</directory>
	</testsuite>

	<filter>
		<whitelist>
			<directory suffix=".php">./classes/</directory>
		</whitelist>
	</filter>

	<logging>
		<log type="coverage-html" target="./testing-log/" charset="UTF-8"
			 yui="true" highlight="true"
			 lowUpperBound="50" highLowerBound="80"/>
	</logging>
</phpunit>

Після запуску тест-кейсу, в теці testing-log генерується три HTML-файли:

  • dashboard.html — містить звіти у вигляді графіків,
  • index.html — містить звіти у вигляді таблиці по всіх тест-кейсах, які були запущені (у моєму випадку це один тест-кейс),
  • user.php.html — звіт по конкретному тест-кейсу, в якому присутній результат аналізу покриття коду, порядково.

На останок

Особисто для мене тема безпеки, оптимізації і автоматизації дуже цікава, і в найближчому майбутньому планую розкрити питання вимірювання навантаження скриптів на сервер. Також, пишіть в коментарях свої ідеї/пропозиції щодо тем майбутніх статей, про які вам було б цікаво дізнатися.

Чистого коду і попутніх завдань.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація