Разработка чрез тестове

от Уикипедия, свободната енциклопедия
(пренасочване от Test Driven Development)

Разработка чрез тестове (на английски: Test first development, на английски: Test-driven development) е проектна методология при разработването на софтуер, при която първо се пише тест и се проверява (верифицира) успешността на този нов тест. След това кодът, който прави тестовия проход, се прилага успешно и след това написаният код се рефакторира. Целта на тестово разработената разработка е да се постигне добър код, който да работи. Така изискванията (requirements) се трансформират в тестове и по-късно в работещ код.

Това е софтуерна инженерна практика, която включва две други практики: Тестово първо развитие и Рефакторинг.

При това се спазва следният работен цикъл: пишат се в тестовата база данни тестови варианти (test cases), които да покрият изискванията за новия изходен код, а чак след това се пише програмният код така, че да покрива тези тестове. Кент Бек, който се счита за създател на този метод, заявява през 2003, че TDD цели един опростен дизайн.

Разработката чрез тестове се свързва с екстремното програмиране, започнато през 1999.

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

Изисквания[редактиране | редактиране на кода]

Разработката чрез тестове изисква от програмистите да създадат автоматизирани модулни тестове (unit tests), които да дефинират изискванията за кода преди самото му писане. Тестовете съдържат твърдения, чиито стойности могат да бъдат истина (true) или лъжа (false). Успешното изпълнение на тестовете потвърждава правилното поведение на софтуера след допълването му с нов код. Често за създаването и автоматичното изпълнение на редица от тестови сценарии програмистите използват тестваща среда като например xUnit.

Работен цикъл[редактиране | редактиране на кода]

  1. Добавяне на тест
    Всяка нова функционалност започва с писането на тест. За да се напише един такъв тест, разработчикът трябва да има ясна представа от спецификацията и изискванията за новата функционалност. Тъй като самата функционалност все още не е написана, резултатът от теста ще е неуспех.
  2. Изпълнение на всички тестове и проверка на новия тест
    Това е проверка за валидността на тестовете и дали новият тест случайно не минава успешно, тогава не е необходим нов код.
  3. Писане на новия код
    Следващата стъпка е да се напише кодът. Този код трябва да удовлетворява изискванията на новите тестове. На това ниво новият код може да не е перфектен, а просто да е направен така, че само да минава тестът. На по-късен етап той ще се подобри.
  4. Изпълнение на всички тестове с успех
    Ако тестовете са успешни, следователно новият код е покрил изискванията. Минаваме към последната стъпка от цикъла.
  5. Подобряване на кода
    Новият код може да бъде подобрен (преработка на код). След всяка промяна е нужно да се провери дали тестовете минават успешно.
Графично представяне на работния цикъл

По-горният цикъл може да започне отново с добавяне на нови тестове.

Стил на програмиране[редактиране | редактиране на кода]

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

Напиши първо тестовете. Тестовете трябва да бъдат написани преди функционалността, която ще се тества. Това има две предимства: 1) създава се възможност програмата да бъде тествана още от самото начало и 2) гарантира, че ще има тестове за всяка нова функционалност.

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

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

Практиките за напреднали при разработката чрез тестове водят до Acceptance Test-driven development (ATDD).

Ползи[редактиране | редактиране на кода]

Проучване през 2005 посочва, че TDD означава писане на повече тестове. А когато програмистите пишат повече тестове, това говори за по-добра продуктивност.

По-рядко се налага на програмистите да ползват дебъгери. Ползвайки TDD с допълнение със система за контрол на версиите (version control system) дава възможност на програмистите бързо да върнат до по-стара успешна версия, ако тестовете не успеят. Това често е по-добре, отколкото дебъгването.

TDD предлага нещо повече от валидация на новата функционалност. Възможно е също така да се определи дизайна на програмата. Вярно е, че при TDD е необходимо повече писане на код, заради писането на модулни тестове. Но общото време за имплементация по-малко. Голямото количество тестове ограничават грешките в кода. Ранното тестване дава възможност проблемите да бъдат хванати навреме по време на цикъла за разработка и съответно поправени. Това намалява времето за дебъгване на по-късен етап.

При TDD кодът става по-модулно насочен и по-гъвкав. Това идва от факта, че програмистът мисли за програмата като за разделена на малки единици, които трябва да се напишат и тестват независимо един от други, а на по-късен етап – сглобени.

Вземайки предвид факта, че кодът е само толкова, колкото да покрие тестовете, идва резултатът, че за „всеки написан ред“ има готов тест. Например, ако един TDD програмист иска да добави else условие към някой if, то той трябва да напише тест за него, който първоначално да минава с неуспех.

Недостатъци[редактиране | редактиране на кода]

  • TDD е трудно да се използва в ситуациите, които за да определят успех или неуспех изискват тестове върху цялостната функционалност на продукта. Примери за това са програми, които използват бази данни или някои, които зависят от специфични мрежови настройки.
  • Необходимо е разбиране от страна на управлението. Цялата организация трябва да вярва в това, че TDD е правилният подход, който трябва да се избере. В противен случай има риск управлението да смята, че това е просто една загуба на време.
  • Има вероятност лошо написаните тестове постоянно да завършват с неуспех. Понякога, когато едни и същи тестове постоянно завършват с неуспех, те биват пренебрегвани и ако възникне истински проблем, то той няма да бъде забелязан.
  • Степента на покритие на даден тест трудно може да бъде променена на по-късен етап след няколко цикъла в TDD. По тази причина с течение на времето оригиналните тестове стават много важни. Една зле направена архитектура, зле измислен дизайн или стратегия за тестване, могат да доведат до неуспешен резултат на доста тестове (вече съществуващи). Важно е възникналите проблеми да бъдат оправени индивидуално. Не е добре да бъдат премахнати тестовете, защото това би довело до неоткрити грешки.
  • Неочаквани проблеми при покритието на тестовете може да възникнат по редица причини. Примерно, ако някой от програмистите не е добре запознат със стратегията на TDD и следователно някои тестове не са написани както трябва. Възможно е и някои тестове да са изтрити, спрени инцидентно по някаква причина в процеса на работа.
  • По принцип модулните тестове се пишат от програмиста, който ще пише по-късно и кода. Така могат да изскочат проблеми от сорта на: Програмистът не е разбрал, че трябва да се направи проверка за коректност на входните параметри. В този случай нито тестовете ще тестват за това, нито ще бъде имплементирано в по-късно написания код. В този случай и тестовете, и желаният код ще бъдат грешни.
  • Голямото количество успешно завършили тестове може да доведе до грешно впечатление за абсолютна сигурност, което да доведе до недостатъчни действия на QA екипа.

Прозрачност на кода[редактиране | редактиране на кода]

Тестващият код трябва да има достъп до кода, който ще тества. От друга страна не трябва да се нарушават правилата за енкапсулация, скрита информация и т.н. По тази причина обикновено един модулен тест за TDD се пише в същия проект, в който е и кода, който ще се тества.

При един обектно ориентиран дизайн достъпът до private данни и методи ще бъде ограничен. По тази причина се изисква допълнителна работа върху модулните тестове. В езици за програмиране като Java private данни могат да бъдат достъпни чрез reflection. Алтернативно на това модулните тестове могат да бъдат поставени в inner клас, създаден за целта, и по този начин те ще имат достъп до недостъпните отвън данни. При .NET Framework и някои други езици за програмиране, могат да бъдат използвани partial класове.

Важно е да се отбележи, че такива хакове при тестване, не трябва да се оставят в крайния код. C# и други езици за програмиране поддържат директиви при компилиране като #if DEBUG … #endif, където може да бъде поставен нужният код за тестване. Това означава, че кодът при крайната версия се различава от кода, който се използва при тестването.

Вижте също[редактиране | редактиране на кода]

Външни препратки[редактиране | редактиране на кода]

  Тази страница частично или изцяло представлява превод на страницата Test-driven development в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​