Единично тестване от начинаещ до начинаещ
Тази публикация ме вдъхнови да напиша тази статия. Предоставя описание на инструментите и малко теоретична информация.
Аз самият тепърва започвам да разбирам модулното тестване и тестването като цяло, така че реших да споделя малко информация по този въпрос. И също така систематизирайте вашите знания и умения. След това ще се опитам да обясня процеса на тестване стъпка по стъпка на прост филистимски език, тъй като не намерих дъвкано описание никъде в Интернет, стъпка по стъпка, така да се каже. Който се интересува и който иска все пак да се опита да разбере, добре дошъл. Няма да пиша какво е автоматизирано тестване и юнит тестване, има Уикипедия за това.
За нашите тестове ще използваме може би най-популярната рамка - PHPUnit. Първо, трябва да го инсталираме. Най-лесният начин да направите това е чрез PEAR. Как да направите това е написано в документацията. Използват се две команди (от документацията):
Естествено пътят до PEAR трябва да бъде в PATH. Когато необходимите файлове бъдат заредени, нашият PHPUnit ще бъде напълно готов да тества нашия код.
И така, да започваме. Нека имаме някакъв модел на данни. Има два атрибута: низ и число. Има метод за настройка и методи за запазване и зареждане на стойности (във файл).
Дефинирахме базовите методи и атрибутите на класа. Тъй като все още не сме чели или написали нищо, по условие връщаме false.
Сега нека оставим нашия модел настрана за известно време и да започнем да тестваме. Тестът е обикновен клас, наследен от базов клас (в нашия случай PHPUnit_Framework_TestCase). Методите от този клас са тестовете. Нека създадем папка за единица за нашия тест.
TestModelTest е нашият тестов клас за класа TestModel. testTrue() е самият тест. В него ние определяме сценарии законкретни случаи. В този тест просто ще проверим дали true е true :) Това става с метода assertTrue. Тези. ние твърдим, че истината е истина. Нека проведем нашия тест. PHPUnit просто трябва да посочи папката, където се намират всички наши тестове.
Ура, нашият тест работи! Да отидем по-нататък.
TDD - Test Driven Development - подход, при който най-грубо казано първо се пишат тестове, а след това постепенно на тяхна база се пише основният клас. Прочетете повече в wikipedia. Да вървим по този път. Вече имаме рамката на модула. Изисквания също. Сега нека напишем тестови случаи въз основа на нашите изисквания.
Описахме и трите случая по три метода. За всеки своето. Сега нека проведем тестовете:
по дяволите! Е, нищо, така трябва да е :) Сега нека добавим малко код към нашия модел.
Мисля, че нищо в кода не трябва да създава затруднения.
Вече е по-добре. Вече минава два пъти повече проверки. Да вървим по ред: 1. testStringCannotBeEmpty. Низът не може да бъде празен. Добавяне на чек:
2. testIntMustBeGreaterThanTenAdnSmallerThanTwenty. Условие 10 setAttributes(20,'test3'); Не сме взели предвид крайния случай! Поправяме:
Изпълнете нашите тестове:
Ура, и трите теста минаха. Нашият модел отговаря на изискванията. Какво се искаше :)
Заключение
И тук можете да получите грант за тестов период на Yandex.Cloud. Необходимо е само да въведете "Habr" в полето "секретна парола".
Чете сега
PHPUnit. Част 04 Тестови среди (Фикстури)
PHPUnit. Част 03 Писане на тестове за PHPUnit
PHPUnit. Автоматични тестове
Коментари 46
Не съм правил тестване на единици. Кажете ми на абстрактно ниво, в какви случаи трябва да използвате тестване на единици?
PS Кодът за тестовете се оказа повече от самия източник.
На себе си, разбира се. Както и с помощта на функционала, няма да разгледате всички случаи.
Е, използва се абстрактно: когато се проверява изпълнението на функционалните спецификации и / или бизнес логиката на приложението, увереността, че по време на следващия рефакторинг половината от методите и / или условията не са отлетяли.
Е, вероятно се смята за готино :)
Рефакторингът е много полезен, но без тестове е и много опасен.
От личен опит мога да кажа, че големи проекти, които имат наистина сложна логика и голямо наследство, са много трудни за преработване без тестове. Тестовете, разбира се, не са панацея. Но на няколко пъти направих елементарни промени, които сериозно повредиха други модули, за които нямах представа. И текущите тестове помогнаха да се открият такива пречки.
Не знам за вас, но сега не съм скептичен относно тестовете. Видях колко са полезни.
Казах ли, че не са необходими тестове? Току-що казах, че някакъв вид абстрактно рефакторинг в бъдеще не мотивира да се пишат тестове. Виждате ли, когато става въпрос за тестване на единици, аргументите за тестове са: - В бъдеще ще ви бъде по-лесно да преработвате - Винаги можете да знаете, че вашата функция isValid() ще върне правилната стойност И примери като „Нашата функция връща true, ние ще я проверим. Сега вижте, ще преработим и ще стартираме теста отново! Еха!". Много е глупаво и не е ясно защо да правя това: мога ръчно да тествам функцията isValid () и никой не рефакторира всеки ден.
Просто трябва да разберете една от основите на автоматизираните тестове: те са _автоматизирани_ и ви позволяват _автоматично_ и бързо да тествате сложен процес, който може да бъде описан в пет редакод, но за да го повторите, ще трябва да щракнете върху четиридесет бутона с мишката. Понякога има повече тестов код от тестов код. Но не е страшно - по-лесно е.
unit tests (когато няма реална база данни и заявки към нея, но има mocks или stubs) покриват публичните методи на класове и интерфейси с всички възможни случаи на използване на метода + всички опции за некоректни входни данни. При правилна организация, за 1 метод - 5-10 модулни теста се пишат за половин час и 1 път. И след това нито ти, нито екипът ти има адски проблеми с това, че някой е променил метода и всички са се сринали и т.н. Тества се само бизнес логиката, а не връзката с база данни, регистрирането и т.н. Това е важно да се разбере.
А с интеграционните тестове (когато има реална база данни/услуга) ще проверите 3-4 типични ситуации, които обхващат заявки към базата данни или услуги и реакцията на системата към отговори/грешки. Тези. тества се връзката, а не логиката. И получавате +30-50% увеличение на времето за разработка и -150% допълнителен извънреден труд, свързан с този вид грешки и сложността на поддръжката и промяната. Приблизителен резултат: не губите време за случая, когато веднага сте написали кода, но след това сте затънали в коригиране на грешки и поддръжка + ако методът не може да бъде обхванат от теста, тогава има проблеми с архитектурата (SOLID нарушение) Това е чисто моят опит.
Тоест, всъщност при разработването на нов клас/метод той веднага се покрива с тестове (те ще бъдат проверени веднага след завършване на разработването на класа/метода) и в бъдеще, когато този клас/метод се промени, не се губи време за тестове и можете веднага да проверите правилната работа на класа.
Правилно ли съм разбрала?
>Поне веднъж трябваше да напиша такъв тест Как започнах да разбирам - да, написах. > например някои функции на сервизния слой (които също се използват от базата данни) Могат да бъдат заменени в методичетене / писане на функции за работа с файлове, върху функциите за работа с базата данни.
Във всеки случай основното е да уловиш същността. Например, дълго време не можех да го разбера, защото не можах да намеря ръководство „за манекени“. Сега изглежда по-просто и бавно пиша тестове за моя проект.
Опцията е още по-сложна: взаимодействие с услуги на трети страни. Например, трябва да уведомим определена услуга за нашите поръчки (например да изпратим заявка до доставчик да изпрати стоки до нас). Как ще тестваме? Всеки път изпращате всякакви боклуци на трети страни? Нека не бъдем обичани. Как да разберете дали са изпратени правилните данни? Тук ще направим това: ще покрием функцията create_order с тестове! И за да сме сигурни, че данните отиват до доставчика, ние просто заключваме функцията send_order_to_mega_service_ltd (order_ >), сега изпълняваме тестовете и виждаме, че след създаването на поръчката (create_order), изграждаме правилната заявка към доставчика (функцията send_order_to_mega_service_ltd (order_id) изгражда необходимия XML и го изпраща по необходимия начин.
Не работя с PHP, но работя с Ruby, но същността на тестването не се променя.