Кіріспе

Тесттік кодты қайталап жазу арқылы кодтау әдісі, содан кейін өндірістік код. Тесттік дамыту (TDD) – бұл автоматтандырылған бірлік деңгейіндегі тест жағдайын жазуды қамтитын код жазу тәсілі, онда тест сәтсіз аяқталады, содан кейін тек тесттің сәтті өтуі үшін қажетті код жазылады, содан кейін тест коды мен өндірістік код қайта құрылады, және бұл жаңа тест жағдайымен қайталанады. Автоматтандырылған тесттерді жазудың баламалы тәсілдері – өндірістік кодты тест кодын жаза бастамас бұрын жазу немесе тест кодын өндірістік кодты жаза бастамас бұрын жазу. TDD-де екеуі де бірге жазылады. TDD 1999 жылы басталған экстремалды бағдарламалаудың тестті бірінші орынға қоятын ұғымдарымен байланысты, бірақ соңғы уақыттарда өздігінен де кең қызығушылық тудырды. Бағдарламашылар бұл ұғымды ескі техникалармен жасалған мұралық кодты жақсарту және түзету үшін де қолданады.

Даму стилі

Сынақпен басқарылатын дамуды қолданудың әртүрлі аспектілері бар, мысалы, "қарапайым болсын, ақымақтықтан сақтасын" (KISS) және "қажеті жоқ нәрсе" (YAGNI) принциптері. Тек сынақтардан өтуге қажетті кодты жазуға назар аударғанда, дизайн көбінесе басқа әдістерге қарағанда таза әрі түсінікті болады. Егер мүмкіндіктің кодын бірінші жазсаңыз, әзірлеушілер мен ұйымдар әзірлеушіні келесі мүмкіндікке итеруге бейім, тіпті сынақты толығымен ұмытып кетуі мүмкін. Алғашқы TDD сынағы тіпті құрастырылмауы мүмкін, себебі оған қажетті сыныптар мен әдістер әлі болмауы мүмкін. Дегенмен, бұл алғашқы сынақ орындалатын талаптардың бастамасы болып табылады. Әрбір сынақ жағдайы бастапқыда сәтсіз аяқталады: Бұл сынақтың шынымен жұмыс істейтінін және қателерді анықтай алатынын қамтамасыз етеді. Бұл көрсетілгеннен кейін, негізгі функционалды іске асыруға болады. Осыдан "сынақпен басқарылатын даму ұраны" пайда болды, ол "қызыл/жасыл/рефакторинг", мұнда қызыл – сәтсіздік, ал жасыл – өтуді білдіреді. Сынақпен басқарылатын даму үнемі сәтсіз сынақ жағдайларын қосу, оларды өту және кодты қайта құру қадамдарын қайталайды. Әр кезеңде күтілетін сынақ нәтижелерін алу әзірлеушінің кодты түсінуін нығайтады, сенімділікті арттырады және өнімділікті жоғарылатады.

Кодтың көріну мүмкіндігі

Сынақ коды, сыналатын кодқа қол жеткізуді қажет етеді, бірақ сынақ ақпаратты жасыру, инкапсуляция және қызығушылықтарды бөлу сияқты қалыпты жобалау мақсаттарына зиян келтірмеуі керек. Сондықтан, бірлік сынақ коды әдетте сыналатын кодпен бірге бірдей жобада немесе модульде орналасады. Объектіге бағытталған жобалауда бұл жеке деректерге және әдістерге қол жеткізуді әлі де қамтамасыз етпейді. Сондықтан, бірлік сынақтары үшін қосымша жұмыс қажет болуы мүмкін. Java және басқа тілдерде, әзірлеуші жеке өрістерге және әдістерге қол жеткізу үшін рефлексияны пайдалана алады. Сонымен қатар, бірлік сынақтарын орналастыру үшін ішкі сыныпты пайдалануға болады, осылайша олар қоршаған сыныптың мүшелері мен атрибуттарын көреді. .NET Framework және басқа кейбір бағдарламалау тілдерінде, жеке әдістер мен деректерді сынақтарға қол жеткізу үшін ішінара сыныптарды пайдалануға болады. Мұндай сынақтардың өндірістік кодта қалмауы маңызды. C және басқа тілдерде, компилятор директивалары, мысалы #if DEBUG #endif, мұндай қосымша сыныптардың және барлық басқа сынақтармен байланысты кодтың айналасына орналастырылуы мүмкін, осылайша олар шығарылған кодқа компиляцияланбайды. Бұл шығарылған кодтың бірлікте сынаған кодтан мүлдем басқа екенін білдіреді. Соңғы шығарылымда аз, бірақ толыққанды, аяғынан аяғына дейін интеграциялық сынақтарды жүйелі түрде жүргізу (басқа нәрселермен қатар) өндірістік кодтың сынақ құралдарының ешқандай аспектілеріне сырттай сүйенбейтінін қамтамасыз ете алады. ТДД тәжірибешілері арасында, олардың блогтарында және басқа жазбаларында, жеке әдістер мен деректерді сынаудың дұрыс екендігі туралы пікірталас бар. Кейбіреулер жеке мүшелердің тек жүзеге асыру ерекшеліктері екенін және оларды сынақтардың санын бұзбай өзгертуге рұқсат ету керек деп санайды. Осылайша, кез келген сыныпты оның қоғамдық интерфейсі немесе кейбір тілдерде "қорғалған" интерфейс деп аталатын оның кіші сыныбы арқылы сынау жеткілікті болуы керек. Басқалары функционалдық маңызды аспектілер жеке әдістерде жүзеге асырылуы мүмкін екенін және оларды тікелей сынау кішірек және тікелей бірлік сынақтарының артықшылықтарын ұсынады дейді.

Сынақ құрылымы

Сынақ жағдайын тиімді құру барлық қажетті әрекеттердің орындалуын қамтамасыз етеді, сынақ жағдайын оқуды жақсартады және орындалу процесін жеңілдетеді. Үйлесімді құрылым өзін-өзі түсіндіретін сынақ жағдайын жасауға көмектеседі. Сынақ жағдайлары үшін әдетте қолданылатын құрылым: (1) дайындық, (2) орындау, (3) тексеру және (4) тазалау. Дайындық: Сыналатын объектіні (СО) немесе жалпы сынақ жүйесін сынақты жүргізуге қажетті жағдайға келтіру. Орындау: СО-ны мақсатты әрекетті орындауға итермелеу/бастау және қайтарым мәндері мен шығыс параметрлері сияқты барлық нәтижелерді тіркеу. Бұл қадам әдетте өте қарапайым. Тексеру: Сынақ нәтижелерінің дұрыс екеніне көз жеткізу. Бұл нәтижелерге орындау кезінде алынған нақты нәтижелер немесе СО-дағы күй өзгерістері кіруі мүмкін. Тазалау: СО-ны немесе жалпы сынақ жүйесін сынақтан бұрынғы күйіне қайтару. Бұл қалпына келтіру келесі сынақты осыдан кейін дереу орындауға мүмкіндік береді. Кейбір жағдайларда, мүмкін болатын сынақ сәтсіздігін талдау үшін ақпаратты сақтау мақсатында, тазалау процесі сынақтың дайындық кезеңінен бұрын басталуы керек. Ішкі ішкіліктерді сынау. Баяу орындалатын сынақтар.

TDD және ATDD

Сынақпен басқарылатын даму, қабылдау сынағымен басқарылатын дамуға (ATDD) байланысты, бірақ одан өзгеше. TDD негізінен, операциялар жиынтығын дұрыс орындайтын жақсы жазылған код бөлігін (функция, класс немесе модуль) жасауға көмектесетін әзірлеушінің құралы болып табылады. ATDD – бұл талаптардың дұрыс айқындалуын қамтамасыз ету үшін клиент, әзірлеуші және тестілеуші арасындағы байланыс құралы. TDD сынақты автоматтандыруды қажет етеді. ATDD қажет етпейді, бірақ автоматтандыру регрессиялық тестілеуге көмектеседі. TDD-де қолданылатын сынақтар көбінесе ATDD сынақтарынан туындауы мүмкін, себебі код бөліктері талаптың бір бөлігін іске асырады. ATDD сынақтарын клиент оқи алатындай болуы керек. TDD сынақтарының оқуға қолайлы болуы міндетті емес.

TDD және BDD

BDD (мінез-құлықты бағытталған әзірлеме) TDD және ATDD тәжірибелерін біріктіреді. Ол алдымен тесттерді жазуды қамтиды, бірақ іске асыру бөлігін тексермейтін, егер мінез-құлықты сипаттайтын тесттерге назар аударады. JBehave, Cucumber, Mspec және Specflow сияқты құралдар өнім иелеріне, әзірлеушілерге және тест инженерлеріне бірлесіп мінез-құлықты анықтауға мүмкіндік беретін синтаксистерді ұсынады, олар кейін автоматтандырылған тесттерге аударылады.

TDD бағдарламалық жасақтамасы

TDD-де пайдалы көптеген тестілеу аялары мен құралдары бар.

xUnit жүйелері

Дамушылар тест жағдайларын жасау және автоматты түрде орындау үшін, көбінесе xUnit деп аталатын, компьютерлік көмек көрсететін тестілеу аяларын (frameworks) пайдалана алады, олар 1998 жылы құрылған SUnit-тен шыққан. xUnit аялары мәлімдеме (assertion) стиліндегі тесттерді тексеру мүмкіндіктерін және нәтижелерді баяндауды қамтамасыз етеді. Бұл мүмкіндіктер автоматтандыру үшін маңызды, себебі олар орындалуды тексеру жұмысын тәуелсіз кейін өңдеуден алып, тест орындалуының бір бөлігіне айналдырады. Осы тест аялары ұсынатын орындалу шеңбері жүйедегі барлық тест жағдайларын немесе әртүрлі кіші топтарын, сондай-ақ басқа да мүмкіндіктерді автоматты түрде орындауға мүмкіндік береді.

TAP нәтижелері

Сынау фреймворктері 1987 жылы жасалған, тілден тәуелсіз Test Anything протоколы арқылы бірлік тесттерінің нәтижелерін қабылдауы мүмкін.

Күрделі жүйелер үшін TDD

Үлкен, күрделі жүйелерде TDD-ні қолдану модульдік архитектураны, жарияланған интерфейстері бар анықталған компоненттерді және платформаға тәуелділікті барынша азайту арқылы жүйелік қабаттарды тиянақты ұйымдастыруды қажет етеді. Осы тәжірибелі әдістер сынақтан өтуге қолайлылықты арттырады және құрастыру мен сынау процесін автоматтандыруға мүмкіндік береді.

Артықшылықтары

2005 жылғы зерттеуде TDD қолдану көбірек тест жазуды білдіреді, ал одан әрі, көбірек тест жазған бағдарламашылар өнімдірек болып көрінеді. Код сапасы және TDD мен өнімділік арасындағы тікелей байланысқа қатысты болжамдар нақты нәтиже бермеді. Жаңа ("greenfield") жобаларда таза TDD қолданған бағдарламашылар, әдетте, жөндеушіні шақыру қажеттілігін сирек сезінетінін хабарлады. Версияны басқару жүйесімен бірге қолданғанда, егер тесттер күтпеген жерден сәтсіз болса, кодты соңғы, барлық тесттерден өткен нұсқасына қайтару, көбінесе, жөндеуден тиімдірек болуы мүмкін. Тестпен басқарылатын даму тек дұрыстықты растаумен ғана шектелмейді, сонымен қатар бағдарлама дизайнын да басқарады. Бірінші кезекте тест жағдайларына назар аудару арқылы, функционалдықты клиенттер қалай пайдаланатынын (бірінші жағдайда, тест жағдайлары) елестету қажет. Осылайша, бағдарламашы іске асырудан бұрын интерфейс туралы ойланады. Бұл артықшылық келісімшарт бойынша жобалауға толықтырады, себебі ол кодқа математикалық талаптар немесе алдын ала пікірлер емес, тест жағдайлары арқылы жақындайды. Тестпен жүргізілетін даму қажет болғанда шағын қадамдар жасауға мүмкіндік береді. Бұл бағдарламашыны қолдағы міндетке назар аударуға мүмкіндік береді, себебі бірінші мақсат – тестті өткізу. Ерекше жағдайлар мен қателерді өңдеу бастапқыда қарастырылмайды, ал осы ерекше жағдайларды тудыру үшін тесттер жеке жүргізіледі. Тестпен басқарылатын даму осылайша жазылған барлық кодтың кем дегенде бір тестпен қамтылғанын қамтамасыз етеді. Бұл бағдарламалау тобына және кейінгі пайдаланушыларға кодқа деген сенімділіктің жоғары деңгейін береді. TDD-мен, TDD-сыз бірлік тесттеріне қарағанда көбірек код қажет болғанымен, Мюллер мен Падбергтің моделіне сүйенсек, кодты іске асырудың жалпы уақыты қысқа болуы мүмкін. Көптеген тесттер кодтағы ақаулардың санын шектеуге көмектеседі. Тестілеудің ерте және жиі жүргізілуі даму циклының басында ақауларды анықтауға көмектеседі, олардың кең тарап, қымбатқа түсетін проблемаларға айналуының алдын алады. Процестің бастапқы кезеңінде ақауларды жою, әдетте, жобаның кейінгі кезеңінде ұзақ және қиын жөндеуден аулақтайды. TDD модульдік, икемді және кеңейтілген кодқа әкелуі мүмкін. Бұл әсер көбінесе әдістемеге сәйкес, бағдарламалық жасақтаманы кішігірім, өздігінен жазылып, тестіленіп, кейін біріктірілетін бірліктер ретінде қарастыруды талап етеді. Бұл кішірек, нақтырақ кластарға, әлсіз байланысқа және таза интерфейстерге әкеледі. Мокативті объектілерді жобалау үлгісін қолдану кодтың жалпы модульдеуіне де үлес қосады, себебі бұл үлгі кодты модульдерді бірлікті тестілеу үшін макеттік нұсқалар мен орналастыру үшін "нақты" нұсқалар арасында оңай ауыстыру үшін жазуды талап етеді. Сәтсіз тесттің нәтижесін беру үшін қажетті кодтан артық код жазылмағандықтан, автоматтандырылған тесттер кодтың барлық жолын қамтиды. Мысалы, TDD әзірлеушісі бар if операторына else тармағын қосу үшін, әзірлеуші алдымен тармақты ынталандыратын сәтсіз тест жағдайын жазуы керек. Нәтижесінде, TDD-дан туындайтын автоматтандырылған тесттер өте мұқият болады: олар кодтың мінез-құлқындағы кез келген күтпеген өзгерістерді анықтайды. Бұл даму циклының кейінгі кезеңдеріндегі өзгерістер басқа функционалдылықты күтпеген жерден өзгерткен кезде туындауы мүмкін мәселелерді анықтайды. Мадейски 200-ден астам бағдарламашымен зертханалық эксперименттер сериясы арқылы TDD практикасының дәстүрлі тесттеу әдісіне немесе дұрыстықты тексеруге қарағанда басымдылығы туралы эмпирикалық дәлелдерді ұсынды, объектілер арасындағы байланыстың төмендеуіне (CBO) қатысты. Орташа әсердің көлемі орташа (бірақ үлкен әсерге жақын) әсерді көрсетеді, бұл жүргізілген эксперименттердің мета-талдауы негізінде маңызды нәтиже болып табылады. Ол жақсы модульдеуді (яғни модульдік дизайнды), оңай қайта пайдалануды және TDD бағдарламалау практикасына байланысты әзірленген бағдарламалық өнімдерді сынауды ұсынады. Бұл бірлік тесттерінің мұқияттығын және ақауларды анықтау тиімділігін көрсетеді. TDD-нің тармақтарды қамтуы бойынша әсерінің көлемі орташа болды, сондықтан ол маңызды әсер деп саналады.

Бағдарламашы үшін психологиялық пайда

Үміт артады: TDD бағдарламашыларға өзгерістер енгізуге немесе жаңа мүмкіндіктерді сенімділікпен қосуға мүмкіндік береді. Кодтың үнемі тестіленіп отыратынын білу, қолданыстағы функционалдылықты бұзу қорқынышын азайтады. Бұл қауіпсіздік желісі, проблемаларды шешуге инновациялық және шығармашылық көзқарастарды қолдануға ынталандырады. Өзгерістерден қорқуды және стрессті азайту: Дәстүрлі әзірлеуде, қателер енгізу қаупі болғандықтан, қолданыстағы кодты өзгерту қиын болуы мүмкін. TDD, толыққанды тест жиынтығымен, бұл қорқынышты азайтады, себебі тесттер өзгерістерден туындаған кез келген мәселені дереу анықтайды. Код базасында тесттердің қауіпсіздік желісі бар екенін білу, бағдарламалаумен байланысты стресс пен алаңдаушылықты азайтады. Бұл бағдарламашыларды тәжірибе жасауға және кодты қайта құруға көбірек бейімдейді. Назарды жақсарту: Бірінші кезекте тесттерді жазу, бағдарламашыларға кодты жазудан бұрын талаптар мен жобаға назар аударуға көмектеседі. Бұл назар, мақсатқа бағытталған және анық кодтауға әкелуі мүмкін, өйткені әзірлеуші әрқашан қандай мақсатқа жетуге тырысып жатыр екенін біледі. Жетістік сезімі және жұмыстан қанағаттану: Тесттерден сәтті өту, жылдам және үнемі жетістік сезімін сыйлап, көңіл-күйді көтереді. Бұл, әсіресе ұзақ мерзімді жобаларда, соңғы мақсат алыс сияқты көрінетін кезде, мотивацияны арттырады. Осы факторлардың барлығы жұмыстан қанағаттануға әкелуі мүмкін. Бағдарламашылар сенімділікке толы болғанда, жұмысына назар аударғанда және бірлесіп жұмыс істейтін команданың мүшесі болғанда, олардың жұмыстан қанағаттану деңгейі айтарлықтай жақсарады.

Шектеулер

Тестпен басқарылатын әзірлемеде, толыққанды функционалдық тесттер табыс немесе сәтсіздікті анықтау үшін қажет болған жағдайларда, бірлік тесттерді кеңінен пайдалануға байланысты жеткілікті тест жүргізілмейді. Мұндай жағдайларға пайдаланушы интерфейстері, дерекқормен жұмыс жасайтын бағдарламалар және нақты желілік конфигурацияларға тәуелді бағдарламалар жатады. TDD әзірлеушілерді мұндай модульдерге кодтың ең аз көлемін енгізуге және сыртқы әлемді бейнелеу үшін макеттер мен дублерлерді пайдалана отырып, тесттен өтетін кітапхана кодын барынша арттыруға ынталандырады. Басқару қолдауы маңызды. Егер ұйымның барлық мүшелері тестпен басқарылатын әзірлеме өнімді жақсартады деп сенбесе, басшылық тесттерді жазуға кеткен уақытты ысырап деп санауы мүмкін. Тестпен басқарылатын әзірлеме ортасында жасалған бірлік тесттер әдетте сол кодты жазып жатқан әзірлеуші жасайды. Сондықтан, тесттер кодпен бірдей көре алмаушылықтарды бөлісе алады: мысалы, әзірлеуші белгілі бір кіріс параметрлерін тексеру қажеттігін түсінбесе, тест те, код та оларды тексермейді. Тағы бір мысал: егер әзірлеуші әзірлеп жатқан модульдің талаптарын дұрыс түсінбесе, код пен олар жасайтын бірлік тесттер бірдей қате болады. Сондықтан, тесттер дұрыс екенін қате көрсетіп өтеді. Көптеген өтетін бірлік тесттер қауіпсіздік сезімін тудыруы мүмкін, нәтижесінде интеграциялық тест және сәйкестік тест сияқты қосымша бағдарламалық қамтамасыз ету тесттері азаяды. Тесттер жобаның техникалық қызмет көрсету шығындарының бір бөлігіне айналады. Жаман жазылған тесттер, мысалы, қатаң кодталған қате жолдары бар тесттер, өзі сәтсіздікке ұшырауы мүмкін және оларды күту қымбат. Бұл әсіресе тұрақсыз тесттерге қатысты. Жалған қателерді үнемі тудыратын тесттер назардан тыс қалуы мүмкін, сондықтан нақты қате пайда болған кезде оны анықтамау мүмкін. Тесттерді оңай күту үшін, мысалы, қате жолдарының қайта пайдалану арқылы жазуға болады, және бұл жоғарыда сипатталған кодты қайта құру кезеңінде мақсат болуы керек. Тесттерді жазу және күту көп уақытты қажет етеді. Сонымен қатар, шектеулі тесттері бар икемді модульдер тесттерді өзгерту қажеттілігінсіз жаңа талаптарды қабылдауы мүмкін. Осы себептерге байланысты, тек қана ерекше жағдайларды немесе деректердің шағын үлгісін тексеру, егжей-тегжейлі тесттер жиынтығынан гөрі түзету оңайырақ болуы мүмкін. TDD циклдері кезінде қол жеткізілген қамту деңгейі мен тест егжей-тегжейлілігі кейінірек оңай қайта жаңартылмайды. Сондықтан, осы бастапқы тесттер уақыт өте келе қымбаттай түседі. Тактика – оны ертерек түзету. Сонымен қатар, егер нашар архитектура, нашар дизайн немесе нашар тесттеу стратегиясы көптеген қолданыстағы тесттердің сәтсіздігіне әкелетін кеш өзгеріске әкелсе, оларды жеке-жеке түзету маңызды. Оларды жай ғана жою, өшіру немесе асығыс өзгерту тесттеу қамтуында анықталмайтын кемшіліктерге әкелуі мүмкін.

Конференция

Бірінші ТДД конференциясы 2021 жылдың шілде айында өтті. Конференциялар YouTube-қа жүктелді.