Основи і tdd на прикладі нового пакета

У першій частині ми налаштували оточення для розробки, застосували кілька правил, взятих у Ліги РНР. і створили два простих, але непотрібних класу - Diffbot і DiffbotException. У цій частині ми будемо мати справу з Розробкою через тестування (Test Driven Development, TDD)

Основи і tdd на прикладі нового пакета

Якщо ви хочете продовження - ознайомтеся з першою частиною статті. або клонують репозиторій з кодом прикладу.

Можливо, ви вже щось чули про PHPUnit, але ось настав момент застосувати його в реальній практиці. Насамперед перевіримо, якщо він встановлений:

Запуск цієї команди повинен видати інформацію зі звітом про один пройдений тесті. Це тест, який за замовчуванням поставляється з шаблонним додатком, і за фактом він перевіряє твердження, що true одно true. Звіт про покриття також буде згенеровано і розміщений в директорії проекту.

Якщо ви відкриєте цей звіт про покриття в браузері, ви повинні побачити, що відсоток покриття тестами нашого проекту дуже малий.

Основи і tdd на прикладі нового пакета

Тепер, коли ми переконалися, що PHPUnit у нас працює, давайте що-небудь протестуємо. На даний момент у нас не так вже й багато коду крім геттеров і сеттерів, які, в общем-то, і не повинні тестуватися. Так що ми можемо тестувати в нашому поточному коді? Ну ... Як щодо валідності переданого при створенні екземпляра об'єкта токена?

Насамперед поглянемо на конфігураційний файл PHPUnit, phpunit.xml.dist. Після того, як ми поміняємо слово "League" на "Diffbot" він повинен виглядати так:

Атрибути основного елемента кажуть PHPUnit, що його звіт повинен бути настільки докладним, наскільки це можливо, що необхідно конвертувати всі типи попереджень і помилок в виключення, а з іншими настройками ви можете ознайомитися в документації PHPUnit. Далі, ми визначаємо набори тестів, які застосовуються до зазначеним Додатком або сценарієм. Один з таких наборів - набір для основного додатки (єдиний, який ми будемо використовувати), і назвали ми його "Diffbot Tesat Suite", визначивши, що директорія tests містить всі наші тести - ви можете помітити, що зразок тесту від Ліги вже знаходиться в даної директорії. Також ми говоримо PHPUnit, що він повинен проігнорувати файли, що лежать в директорії src /. так як запускати ми хочемо тільки тести, а не наші класи. І, нарешті, ми налаштовуємо логирование - що, де і як входить в звіт.

Давайте напишемо наш перший тест. В директорії tests створіть файл DiffbotTest.php. Якщо ви користуєтеся PhpStorm - цей процес практично автоматизований:

Не забудьте перевірити, що простір імен у файлі composer.json відповідає цьому:

Тепер ви можете видалити зразок тесту ExampleTest (також як і клас SkeletonClass), і замініть вміст класу DiffbotTest на наступне:

У цьому простому прикладі ми тестуємо статичний метод Diffbot :: setToken. Ми використовуємо синтаксис Постачальників Даних (DataProviders) для циклічного тестування наборів даних. Це також дозволяє нам дізнатися, які ключі не є вірними, замість того, щоб перевіряти викид виключення. Якщо зараз ми запустимо тест і подивимося на покриття, то ми повинні побачити щось подібне:

Основи і tdd на прикладі нового пакета

Я бачу досягнення, і в мені прокидається бажання бачити якомога більше зеленого. Давайте перевіримо створення екземпляра класу.

Ці методи покривають всі випадки в конструкторі - інстанцірованія без токена і без встановленого глобально, інстанцірованія з глобально встановленим токеном, і інстанцірованія тільки за допомогою параметра. Але запустивши тест, ми бачимо, що він завершується з помилкою. Це відбувається тому, що клас Diffbot все ще зберігає статичну властивість, встановлене в попередньому тесті, отже нам не вистачає статичного токена за замовчуванням в другому тесті. Це загальна проблема тестування глобальних і статичних властивостей. Щоб обійти її, зробимо так, щоб кожен тест в класі DiffbotTest виконувався в окремому процесі. Це сповільнить виконання, але ми будемо впевнені, що для кожного випадку у нас чисте і не засмічене оточення.

Тепер, коли ви запустите тест, подивіться на покриття - ви побачите, що все стало зеленим!

Основи і tdd на прикладі нового пакета

Взагалі-то, це свого роду анти-патерн - необхідність запускати тести в різних процесах, - який зазвичай вказує на те, що в архітектурі класу щось неправильно, але я все ж знайшов найкращий підхід до тестування цього випадку. Статична властивість в класі Diffbot має бути змінним для простоти використання. Якщо у вас є пропозиції, як це можна поліпшити - я весь увага. Альтернативний підхід до вирішення цієї проблеми - створити метод reset. або додатковий сетер, який можна використовувати для ручного повернення класу в первісний стан, але я уникаю таких підходів, щоб не захаращувати свої класи логікою, призначеної для тестування. Взагалі-то це можна вирішити за допомогою backupStaticAttributes. але у мене не вийшло змусити його працювати.

TDD (Розробка через тестування)

У TDD насамперед треба обдумати плановану функціональність, потім написати під неї тести (запустити їх, і отримати помилки), а потім вже реалізувати робочу функціональність, щоб тести відпрацьовували як треба. Ось де тестування управляє розробкою, тобто розробка через тестування. Це саме те, що ми будемо робити в цьому розділі.

Diffbot, як сервіс, надає кілька API за замовчуванням:

Згідно з документацією, кожне API повертає схожий відповідь (все повертають валідний JSON), але набір повертаються полів зазвичай відрізняється. Ось як я бачу клас Diffbot в стадії фінального продукту: в ньому є методи для доступу до кожного виду API, і кожен тип API - це окремий клас, який нам ще належить розробити. Все API класи успадковуються від одного абстрактного класу API, який містить набір сеттерів для загальних полів, а кожен API клас додатково вносить свої настроюються поля. Загалом, за підсумком я хочу отримати подібну можливість використання:

Тестування абстрактних класів

Ми визначили кілька постачальників даних, як і в першому тесті. Також у нас є метод, який створює наш mock-об'єкт, так що ми можемо викликати його при необхідності. Потім ми створюємо методу тесту для всіх сценаріїв - немає аргуманта таймаута, невірне значення аргументу і вірне значення аргументу. Виняток ми очікуємо тільки в разі неправильного значення аргументу.

Якщо ми запустимо тест - то ми отримаємо помилку:

Основи і tdd на прикладі нового пакета

Запуск тесту генерує вже нову помилку:

Основи і tdd на прикладі нового пакета

Ух ти! Ми поламали PHPUnit! Взагалі-то я жартую, все в порядку. Тут йдеться про те, що у нас в класі немає методу setTimeout (). який потрібен тесту - передбачається, що він повинен бути у mock-об'єкта. Давайте внесемо зміни в Api.php.

Перезапустивши тест отримаємо:

Основи і tdd на прикладі нового пакета

Тепер ми кудись дісталися. Тепер додамо завершальну реалізацію необхідної нам функціональності. Відредагуємо тіло методу setTimeout таким чином:

Разом з логікою ми додали документує блок, і змусили метод повертати екземпляр використовуваного класу, так що ми можемо складати ланцюжки методів. Перезапускаємо тести, всі повинні пройти. Подивившись на покриття повинні побачити 100%.

висновок

У другій частині ми почали ознайомлення з TDD з введення PHPUnit і використання його для розробки деякого функціоналу нашого пакета. Ви можете викачати повний код другій частині статті з цієї гілки. У наступній частині ми продовжимо розробляти пакет з використанням методів, описаних в цій статті, а також додамо ще один аспект - підміну даних. Не перемикайтеся!

5 останніх уроків рубрики "PHP"

Коли мова йде про безпеку веб-сайту, то фраза "фільтруйте все, екрануйте все" завжди буде актуальна. Сьогодні поговоримо про фільтрації даних.

  • Expressive 2 підтримує можливість підключення інших ZF компонент за спеціальною схемою. Не всім подобається це рішення. У цій статті ми розповімо як поліпшили процес підключення декількох модулів.

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

  • Підбірка з декількох видів PHP пісочниць. На деяких ви в режимі online зможете потестить свій код, але є так само рішення, які можна впровадити на свій сайт.

    Основи і tdd на прикладі нового пакета

    За рахунок отримання інформації відразу по двох каналах (зір і слух) ефективність навчання значно перевершує навчання по книгах. А домашні завдання і онлайн-тести дозволять вам постійно думати на мові, що вивчається і відразу перевіряти свої знання!

    Основи і tdd на прикладі нового пакета

    Основи і tdd на прикладі нового пакета

    Якщо ви давно хочете як слід вивчити HTML, то у мене для Вас є чудова новина!

    Основи і tdd на прикладі нового пакета

    Якщо ви вже вивчили HTML і хочете рухатися далі, то наступним кроком буде вивчення технології CSS.

    Основи і tdd на прикладі нового пакета

    Якщо ви хочете розібратися з поняттями домену і хостингу, навчитися створювати бази даних, закачувати файли сайту на сервер по FTP, створювати піддомени, налаштовувати поштові скриньки для свого сайту і стежити за його відвідуваністю, то цей курс створений спеціально для вас!

    Схожі статті