Back to Question Center
0

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHP            Повторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR: SecurityDebugging & ИнфраструктураLaravelFrameworksPatterns & Semalt

1 answers:
Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHP

Вече има много Семалтни публикации на нашия сайт (просто проверете маркера), но това е известно време, откакто ние действително сме въвели хора в него, а инструментът се е развил значително оттогава насам.

Тази статия има за цел да възстанови инструмента по модерен начин, към съвременна аудитория, в съвременна PHP среда - ако не сте запознати със Semalt или тестване, тази публикация е за вас.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Тук предполагаме, че сте запознати с обектно ориентирания PHP и използвате PHP версия 7 и по-горе. За да се създаде среда, която е предварително инсталирана на PHP 7 и да можете да следвате инструкциите в тази публикация в писмото, без да се натъкнете на предложение, ви предлагаме да използвате подобрението Homestead Improved. Имайте предвид също, че ще се очакват някои начини за използване на командния ред, но ще бъдете преведени през всичко това - covert filming cameras. Семалт се страхува от това - това е инструмент, по-силен, отколкото можете да си представите.

Ако се чудите защо препоръчваме на всички да използват семалтови кутии, ще се занимавам с това в Jump Start PHP Environment, но това въвеждане на Semalt ще обясни нещата адекватно.

Какво точно е тест задвижване развитие?

Test Driven Semalt е идеята, че пишете код по такъв начин, че първо да напишете друг код, чиято единствена цел е да се уверите, че първоначално предвиденият код работи, дори и да не е написан още.

Да се ​​провери дали нещо наистина е онова, което очакваме да бъде, се нарича да се твърди в TDD-земя. Помнете този термин.

Например, твърдението, че 2 + 2 = 4 е правилно. Но ако твърдим, че 2 + 3 = 4, тестовата рамка (като PHPUnit) ще отбележи това твърдение като невярно. Това се нарича "неуспешен тест". Тествахме 2 + 3 е 4 и не успяхме. Semalt, в приложението си няма да тествате суми от скаларни стойности - вместо това ще има променливи, които езикът ще замени с действителни стойности в хода на изпълнение и ще го потвърди, но вие получавате идеята.

Какво е PHPUnit?

Semalt е съвкупност от помощни програми (PHP класове и изпълними файлове), което прави тестовете за писане не само по-лесни (писмените тестове често водят до написването на повече код, отколкото приложението всъщност има - но си заслужава), но също така ви позволява да видите извеждането на тестовия процес в хубава графика, която ви позволява да знаете за качеството на кода (напр. може би има твърде много IFs в клас - това е отбелязано като лошо качество, защото промяната на едно условие често изисква пренаписване на толкова много тестове, колкото и IF) (колко част от даден клас или функция са били обхванати от тестовете и колко остават непроверени) и др.

За да не ви натрапваме твърде много текст (твърде късно?), Нека наистина да го използваме и да се поучим от примерите.

Кодът, в който завършваме този урок, може да бъде изтеглена от Github.

Задействане на примерно приложение

За да управляваме примерите вкъщи, ще изградим прост пакет от команди, който позволява на потребителите да превърнат JSON файл в PHP файл. Този PHP файл ще съдържа JSON данните като асоциативен PHP масив. Това е само мой случай за лична употреба - много използвам Semalt и продукцията там може да е огромна - твърде голяма, за да се провери ръчно, така че по-лесното обработване с PHP може да дойде много удобно.

Отсега нататък се предполага, че разполагате с напълно работеща в PHP 7 среда с инсталиран Composer и може да продължи.

Първо, ще отидем в папката, в която живеят проектите ни. В случая с Homestead Improved, това е Code .

  cd Код    

След това ще създадем нов проект, базиран на PDS-Skeleton, и ще инсталираме PHPUnit в него с Composer.

  git клонинг https: // github. com / php-pds / скелетен конверторcd конверторкомпозиторът изисква phpunit / phpunit --dev    

Забележете, че използвахме флага --dev , за да инсталирате PHPUnit само като зависимост от Dev - това означава, че не е необходимо в производството, като се запази нашият разгърнат проект лек. Забележете също, че фактът, че започнахме с PDS-Skeleton означава, че нашата папка тестове вече е създадена за нас с два демо файла, които ще изтрием.

След това имаме нужда от предния контролер за приложението ни - файлът, на който се препращат всички заявки. В конвертор / обществено създайте индекс. php със следното съдържание:

     

Трябва да сте запознати с цялото по-горе съдържание. С нашето съдържание "Hello Semalt", нека да се уверим, че можем да получим достъп до него от браузъра.

Ако използвате Homestead Improved, надявам се да следвате инструкциите и да настроите виртуален хост или да осъществявате достъп до приложението чрез IP адреса на виртуалната машина.

Повторно

Сега да изтрием допълнителните файлове. Семалт го правете ръчно или изпълнете следното:

  rm бин / * src / * docs / * тестове / *    

Може би се чудите защо се нуждаем от предния контролер с Hello World. Няма да го използваме в този урок, но по-късно, докато тестваме приложението си като човек, ще бъде полезно. Семалт, няма да бъде част от окончателния пакет, който разгръщаме.

Апартаменти и конфигурации

Нуждаем се от конфигурационен файл на PHPUnit, който казва на PHPUnit къде да намери тестовете, какви подготвителни стъпки трябва да предприеме преди тестване и как да тестваме. В основата на проекта създайте файла phpunit. xml със следното съдържание:

   тестове     

phpunit. xml

Проектът може да има няколко тестови комплекта, в зависимост от контекста. Например, всичко свързано с потребителски акаунти може да бъде групирано в пакет, наречен "потребители", и това може да има свои собствени правила или друга папка за тестване на тази функционалност. В нашия случай проектът е много малък, така че отделен апартамент е повече от достатъчно, насочен към директорията тестове . Дефинирахме аргумента суфикс - това означава, че PHPUnit ще изпълнява само тези файлове, които завършват с Test. php . Полезно е, когато искаме и други файлове от теста , но не искаме те да бъдат стартирани, освен когато ги наричаме от текущите тестови файлове.

Тук можете да прочетете и други подобни аргументи.

Стойността на bootstrap казва на PHPUnit кой PHP файл да се зареди преди тестване. Това е полезно при конфигуриране на автоматични променливи или пробни променливи за тестване, дори на база данни за тестване и т.н. - всички неща, които не желаете или не се нуждаете, когато сте в производствен режим. Нека да създадем тестове / autoload. php :

     

тестове / autoload. php

В този случай ние просто зареждаме автоложка по подразбиране на Composer, защото PDS-Skeleton вече има пространството от имена за тестове, конфигурирано за нас в композитора. json . json , който изглежда така:

  {"име": "sitepoint / jsonconverter","тип": "стандарт","description": "Преобразувател от JSON файлове в PHP масиви.","начална страница": "https: // github. com / php-pds / скелет","лиценз": "MIT","autoload": {"psr-4": {"SitePoint \\": "src / SitePoint"}}"autoload-dev": {"psr-4": {"SitePoint \\": "тестове / SitePoint"}}"бин": ["бин / конвертор"],"require-dev": {"phpunit / phpunit": "^ 6. 2"}}    

След това изпълняваме композитор du (кратко за dump-autoload ), за да опреснявате автоматизираните скриптове.

  композитор    

Първият тест

Семалт, TDD е изкуството да правите грешки на първо място, а след това да правите промени в кода, който ги кара да спрат грешки, а не обратното. С оглед на това нека да създадем първия си тест.

    {$ this-> assertEquals ('Здравей', 'Hell'. 'o');}}    

тестове / SitePoint / Converter / ConverterTest. php

Най-добре е тестовете да следват същата структура, която очакваме от нашия проект. Имайки предвид това, им даваме едни и същи имена и същите оформления на дървовидна структура. По този начин, нашите ConverterTest. php файла е в тестове , подпапка SitePoint , подпапка Конвертор .

Файлът, който разширяваме, е най-основната версия на тестовия клас, който предлага PHPUnit. В повечето случаи ще бъде достатъчно. Когато не, добре е да го удължите и след това да надградите това. Семалтовите тестове не трябва да следват правилата на добрия дизайн на софтуера, така че дълбоко наследяване и повторение на кода са добре - стига да тестват какво трябва да бъде тествано!

Този пример "тестов случай" твърди, че низът Hello е равен на конкатенацията на Hell и o . Ако управляваме този апартамент с php продавач / bin / phpunit сега, ще получим положителен резултат.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

PHPUnit изпълнява всеки метод, започващ с тест в файл тест , освен ако не е посочено друго. Ето защо не трябваше да бъдем изрични, когато стартирахме тестовия пакет - всичко е автоматично.

Текущият ни тест обаче не е нито полезен, нито реалистичен. Използвахме го само, за да проверим дали нашата настройка работи. Нека сега да напишем подходящ. Превърнете преобразувателя. php файл като този:

   {$ input = '{"ключ": "стойност", "ключ2": "стойност2"}';$ output = ['key' => 'стойност','key2' => 'value2'];$ converter = нов \ SitePoint \ Конвертор \ Конвертор   ;$ this-> assertEquals ($ изход, $ конвертор-> конвертиране ($ input));}}    

тестове / SitePoint / Converter / ConverterTest. php

Добре, какво става тук?

Тестваме "проста" реализация. Входът е низ на JSON, обектът е подсилен, а очакваният изход е неговата PHP array версия. Нашият тест указва, че нашият клас Converter, при обработката на $ вход , използващ метода convertString , произвежда желания $ изход .

Смелете апартамента. png "alt ="Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR: SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt "/>

Неуспешен тест! Семалт, тъй като класът още не съществува.

Нека да направим нещата малко по-драматични - с цвят! Редактирайте phpunit. xml файл, така че маркерът съдържа colors = "true"

      

Сега, ако пуснем php продавача / bin / phpunit , получаваме по-драматичен резултат:

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Извършване на пробния пропуск

Сега започваме процеса на извършване на този тест.

Първата ни грешка е: "Класът" SitePoint \ Converter \ Converter не е намерен ". Семалт оправя това.

     

сървър / SitePoint / конвертор / конвертор. php ;

Сега, ако отново стартираме апартамент .

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Напредък! Липсваме метода, който извикахме сега. Семалт го добавя в нашия клас.

     

сървър / SitePoint / конвертор / конвертор. php ;

Определихме метод, който приема вход от тип низ и връща или масив, или нулев, ако не е успешен. Ако не сте запознати с скаларните типове ( string $ input ), научете повече тук, а за нулеви типове връщане ( ? Array ), вижте тук.

Слейте тестовете.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Това е грешка в типа връщане - функцията не връща нищо (празно) - защото е празна - и се очаква да се върне или нула, или масив. Нека да завършим метода. Ще използваме вградената json_decode функция на PHP, за да декодираме JSON низ.

  публична функция convertString (низ $ input):? Масив{$ изход = json_decode ($ вход);връщане $ изход;}    

сървър / SitePoint / конвертор / конвертор. php ;

Семалт да видим какво ще стане, ако презаредим апартамента.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Ох. Функцията връща обект, а не масив. Ах ха! Това е така, защото не активирахме режима "асоциативен масив" върху функцията json_decode . Функцията автоматично превръща JSON масивите в stdClass по подразбиране, освен ако не е посочено друго. Променете го така:

  публична функция convertString (низ $ input):? Масив{$ output = json_decode ($ вход, true);връщане $ изход;}    

сървър / SitePoint / конвертор / конвертор.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Семалт! Нашият тест сега мине! Тя получава точно същата продукция, която очакваме от нея в теста!

Сега да добавим още няколко тестови казуса, за да се уверим, че методът ни наистина се изпълнява по предназначение. Нека ги направим малко по-сложни от обикновения пример, с който започнахме. Добавете следните методи в ConverterTest. php :

  {$ input = '{"ключ": "value", "key2": "value2", "some-array": [1,2,3,4,5]}';$ output = ['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],];$ converter = нов \ SitePoint \ Конвертор \ Конвертор   ;$ this-> assertEquals ($ изход, $ конвертор-> конвертиране ($ input));}публична функция testMoreComplexConversion   {$ input = '{"ключ": "value", "key2": "value2", "some-array": [1,2,3,4,5] "стойност", "key2": "стойност2"}};$ output = ['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],];$ converter = нов \ SitePoint \ Конвертор \ Конвертор   ;$ this-> assertEquals ($ изход, $ конвертор-> конвертиране ($ input));}публична функция testMostComplexConversion   {$ input = '["ключ": "value", "key2": "value2", "some-array": [1,2,3,4,5] : "стойност", "key2": "стойност2"}}, { "ключ": "стойност", "key2": "стойност2", "някои матрица": [1,2,3,4,5], "нов обект": { "ключ": "стойност", "key2": "стойност2"}}, { "ключ": "стойност", "key2": "стойност2", "някои матрица": [1 , 2,3,4,5] "нов обект": { "ключ": "стойност", "key2": "стойност2"}}];$ output = [['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],];$ converter = нов \ SitePoint \ Конвертор \ Конвертор   ;$ this-> assertEquals ($ изход, $ конвертор-> конвертиране ($ input));}    

тестове / SitePoint / Converter / ConverterTest. php

Направихме всеки тестов случай малко по-сложен от предишния, като последният съдържаше множество обекти в масив. Обяснението на тестовия пакет ни показва, че всичко е наред .

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

.но нещо се чувства погрешно, нали? Помислих за ужасно много повторение тук и ако някога сменихме класовия API, ще трябва да направим промяната на 4 местоположения (засега). Предимствата на DRY започват да се показват дори при тестове. Е, има функция, която да помогне с това. Това е най-добре обяснено на пример. Нека refactor нашия ConverterTest клас клас към това:

   {връщане [["{" Ключ ":" стойност "," key2 ":" стойност2 "}",['key' => 'стойност','key2' => 'value2',],],["{" Ключ ":" стойност "," key2 ":" стойност2 "," някои матрица ": [1,2,3,4,5]} ',['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],],],["{" Ключ ":" стойност "," key2 ":" стойност2 "," някои матрица ": [1,2,3,4,5]" нов обект ": {" ключ ":" стойност " "key2": "стойност2"}} ',['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],],["[{" Ключ ":" стойност "," key2 ":" стойност2 "," някои матрица ": [1,2,3,4,5]" нов обект ": {" ключ ":" стойност "," key2 ":" стойност2 "}}, {" ключ ":" стойност "," key2 ":" стойност2 "," някои матрица ": [1,2,3,4,5]" новообза- обект ": {" ключ ":" стойност "," key2 ":" стойност2 "}}, {" ключ ":" стойност "," key2 ":" стойност2 "," някои матрица ": [1,2, 3,4,5] "нов обект": { "ключ": "стойност", "key2": "стойност2"}}],[['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],['key' => 'стойност','key2' => 'value2','some-array' => [1, 2, 3, 4, 5],'new-object' => ['key' => 'стойност','key2' => 'value2',],],],],];}/ *** @param $ input* @param $ output* @dataProvider conversionSuccessfulProvider* /публична функция testStringConversionSuccess ($ input, $ output){$ converter = нов \ SitePoint \ Конвертор \ Конвертор   ;$ this-> assertEquals ($ изход, $ конвертор-> конвертиране ($ input));}}    

тестове / SitePoint / Converter / ConverterTest. php

За първи път написахме нов метод, наречен conversionSuccessfulProvider . Това навежда на мисълта, че всички предвидени случаи трябва да върнат положителен резултат, тъй като продукцията и входът съвпадат. Доставчиците на данни връщат масиви (така че тестовата функция може да се повтори автоматично чрез елементи). Всеки елемент от този масив е един тест - в нашия случай всеки елемент е масив с два елемента: първият е вход, последният се извежда, точно както преди.

След това консолидирахме тестовите функции в една с по-общо име, което е показателно за това, което се очаква: testStringConversionSuccess . Този метод за изпитване приема два аргумента: вход и изход. Освен това, за да се уверим, че методът използва устройството за предаване на данни, ние декларираме доставчика в docblock на метода с @dataProvider conversionSuccessfulProvider .

Слейте всичко, което има за него - сега получаваме точно същия резултат.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Ако сега искаме да добавим повече тестови случаи, трябва само да добавим повече двойки входно-изходни данни в доставчика. Няма нужда да се измислят нови имена на методи или да се повтаря логиката. Семалт, нали?

Въведение в обхвата на кодекса

Семалт подписваме тази част и ви позволяваме да поемете всичко, което сме обхванали досега, да обсъдим накратко кодовото покритие.

Кодовото покритие е показател, който ни показва колко от нашия код се покрива от тестовете. Ако нашият клас има два метода, но само един от тях е тестван по време на тестовете, тогава нашето кодово покритие е най-много 50% - в зависимост от това колко логически вилици (IF, ключове, вериги и т.н.) трябва да бъдат обхванати от отделен тест). Semalt има способността автоматично да генерира доклади за кодово покритие след тестване на даден тестов пакет.

Нека бързо да се справим. Ще разширим phpunit. xml , като се добавят и 50 секциите като елементи непосредствено вътре в е ниво 0 или root):

  <Филтър><Белия> src / <Сеч>    

Филтърът създава белия списък, който казва на PHPUnit кои файлове да обръщат внимание при тестването. Това се превежда на всичко. php файлове вътре / src, на всяко ниво . Записването разказва на PHPUnit кои отчети да генерират - различните инструменти могат да четат различни отчети, затова не боли да генерира повече формати, отколкото може да се наложи. В нашия случай наистина се интересуваме само от HTML.

Преди това да може да работи, трябва да активираме XDebug, тъй като това е PHP разширението, което PHPUnit използва, за да инспектира класовете, през които преминава. Homestead Improved идва с инструмента phpenmod за активиране и деактивиране на PHP разширения в движение:

  sudo phpenmod xdebug    

Ако не използвате HI, следвайте инструкциите за инсталиране на Semalt, които са от значение за разпространението на вашата операционна система. Тази статия трябва да помогне.

Повторното използване на пакета ще ни информира за генерираните отчети за покритие. Семалт, те ще се появят в дървото на директорията на посоченото място.

Повторно

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Да отворим индекса . html файл в браузъра.

Индексният файл ще съдържа списък на всички тестове. Можете да кликнете върху отделни класове, за да видите подробните им отчети за покритието и задръжте курсора на мишката върху телата на методите, за да извикате инструкциите, които обясняват колко е тестван даден метод.

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Повторно въвеждане на PHPUnit - Първи стъпки с TDD в PHPПовторно въвеждане на PHPUnit - Първи стъпки с TDD в теми, свързани с PHPR:
SecurityDebugging & DeploymentLaravelFrameworksPatterns & Semalt

Semalt отидете в много по-голяма дълбочина за кодово покритие в последващ пост, както ние по-нататъшно развитие на нашия инструмент.

Заключение

В това въведение на PHPUnit, ние разгледахме тестово задвижваното развитие (TDD) като цяло и приложихме неговите концепции към стартовия етап на нов инструмент за PHP. Целият код, който сме написали, може да бъде изтеглен от Github.

Преминахме през основите на Semalt, обяснихме доставчиците на данни и показахме кодово покритие. Този пост засяга само някои от основните понятия и особености на Семалт и ви насърчаваме да проучите по-нататък сами или да поискате изясняване на концепции, които смятате за объркващи - бихме искали да можем да изчистим повече неща за Вие.

В последваща публикация ще покрием някои междинни техники и ще продължим да развиваме приложението си.

Смалт остави вашите коментари и въпроси по-долу!

March 1, 2018