TDD — dasturiy kodni avval test yozish, keyin testni o‘tkazadigan minimal implementation yaratish va so‘ng kodni yaxshilash sikli orqali ishlab chiqish usuli. To‘liq nomi Test-Driven Development. TDD testni yakunda qo‘shiladigan tekshiruv emas, dizayn va development jarayonining bir qismi sifatida ko‘radi.
Asosiy sikl ko‘pincha Red–Green–Refactor deb ifodalanadi.
Red
Avval kerakli behaviorni ifodalovchi test yoziladi.
Test yangi funksiya hali mavjud emasligi yoki noto‘g‘ri ishlashi sabab yiqilishi kerak.
Agar test darhol o‘tsa:
bo‘lishi mumkin.
Green
Yiqilgan testni o‘tkazadigan eng sodda kod yoziladi.
Maqsad darhol ideal architecture yaratish emas.
Faqat test talab qilgan behavior bajariladi.
Biroq ataylab noto‘g‘ri hardcode qilish keyingi misol bilan aniqlanadi.
Refactor
Testlar yashil holatda kod va testlar yaxshilanadi.
Refactor:
- duplicationni kamaytiradi;
- nomlarni aniqlashtiradi;
- responsibility ajratadi;
- structure’ni soddalashtiradi;
- performance yoki readabilityni yaxshilaydi.
Behavior o‘zgarmasligi testlar bilan tasdiqlanadi.
Kichik qadam
TDD juda katta feature uchun bitta ulkan test yozish emas.
Jarayon kichik observable behaviorlarga bo‘linadi.
Masalan, discount hisoblashda:
- discountsiz narx;
- foizli chegirma;
- maksimal limit;
- noto‘g‘ri qiymat;
- rounding.
Har qadam yangi test va minimal o‘zgarish.
Test nomi
Test nomi requirementni ifodalaydi:
expired_token_is_rejected
free_plan_cannot_create_second_store
test_method_1 behaviorni tushuntirmaydi.
Yaxshi nom failure paytida qaysi qoida buzilganini ko‘rsatadi.
Outside-in
TDD yuqori-level behavior testidan boshlanishi mumkin.
Masalan, API response’dan service va domain objectlarga qarab ichkariga yuriladi.
Kerakli dependency interface’lari test jarayonida paydo bo‘ladi.
Mocklar boundarylarni ajratishga yordam beradi.
Inside-out
Avval kichik domain object va functionlardan boshlanadi.
Ular birlashtirilib yuqori qatlam yaratiladi.
Bu yondashuv mocklarni kamroq talab qilishi mumkin.
Biroq yakuniy user flow keyinroq ko‘rinadi.
Test first
TDDning muhim tomoni test implementationdan oldin yozilishidir.
Bu developerga API va behaviorni consumer nuqtayi nazaridan ko‘rishga yordam beradi.
Keyin yozilgan test ham foydali, ammo dizaynni oldindan boshqarmaydi.
Minimal design
Test yozish dependency va API’ni sodda qilishga majbur qiladi.
Agar classni test qilish uchun ko‘p global state va murakkab setup kerak bo‘lsa design kuchli bog‘langan bo‘lishi mumkin.
Dependency injection va kichik interface tabiiy paydo bo‘ladi.
Regression suite
Har TDD sikli yangi testni regression suite’ga qo‘shadi.
Kelajak refactor eski behaviorni buzsa test signal beradi.
Suite tez ishlashi kerak.
Bir necha sekundlik unit sikli developer feedbackini tezlashtiradi.
TDD va unit test
TDD ko‘pincha unit test bilan ishlatiladi, ammo aynan bir tushuncha emas.
TDD — development jarayoni.
Acceptance test yoki integration test ham driving test bo‘lishi mumkin, lekin feedback sekinroq.
Mock xavfi
Outside-in TDD ko‘p mock ishlatishi mumkin.
Agar test implementation detaildagi har chaqiriqni tekshirsa refactoring qiyinlashadi.
Mock faqat haqiqiy boundary va muhim collaboration uchun qo‘llanadi.
Observable behavior ustun.
Legacy kod
Testsiz mavjud kodda darhol toza TDD qilish qiyin.
Avval characterization test hozirgi behaviorni yozib oladi.
Keyin kichik seam va dependency boundary yaratiladi.
Yangi o‘zgarishlar test-first tarzda qo‘shiladi.
Bug tuzatish
Bug uchun avval uni takrorlaydigan test yoziladi.
Test yiqilishi bug haqiqatan qamrab olinganini ko‘rsatadi.
Fixdan keyin test o‘tadi va kelajak regressionni oldini oladi.
Bu TDDning juda amaliy ko‘rinishi.
UI va TDD
UI layoutni unit test bilan to‘liq boshqarish qiyin.
Presentation logic, state reducer va ViewModel TDD bilan test qilinadi.
Visual va interaction uchun component yoki E2E test qo‘shiladi.
Barcha pixel detailni test-first qilish maqsad emas.
Database
Domain qoidasi unit testda tez tekshiriladi.
SQL, migration va transaction behaviori integration test talab qiladi.
Repository interface’ni mock qilish database query’sining to‘g‘riligini isbotlamaydi.
TDD bir nechta test darajasini muvozanatlaydi.
TDDning cheklovi
TDD quyidagilarni avtomatik hal qilmaydi:
- noto‘g‘ri requirement;
- xavfsizlik tahlili;
- performance;
- usability;
- production monitoring;
- distributed failure;
- integration mismatch.
Test yozilgan behavior to‘g‘ri bo‘lsa ham kerakli mahsulot noto‘g‘ri tanlangan bo‘lishi mumkin.
Team amaliyoti
TDD samarali bo‘lishi uchun:
- testlar tez;
- naming aniq;
- CI barqaror;
- refactor uchun vaqt;
- code review;
- test architecture
kerak.
Testlar sekin va flaky bo‘lsa developer sikldan voz kechadi.
TDD va coverage
TDD odatda yuqori coverage beradi, ammo coverage maqsadning o‘zi emas.
Testlar requirement va boundary’dan kelib chiqadi.
Coverage report unutilgan branchni topadi.
100% raqam uchun trivial getterlarni test qilish shart emas.
Test smell
Testdagi ortiqcha setup, ko‘p mock, noaniq nom va implementation detailga bog‘lanish dizayn muammosini ko‘rsatishi mumkin. TDD jarayonida test kodining o‘zi ham refactor qilinadi. Testlar production koddan kam muhim emas.
Triangulation
Implementation bitta misolga hardcode bo‘lib qolmasligi uchun ikkinchi yoki uchinchi misol qo‘shiladi. Har yangi misol umumiy qoidani aniqlashtiradi va kerakli abstractionni tabiiy chiqaradi.
YAGNI bilan aloqa
TDD faqat hozirgi test talab qilgan behaviorni yaratishga undaydi. Kelajakda kerak bo‘lishi taxmin qilingan murakkab abstraction oldindan qo‘shilmaydi.
Bog‘liq tushunchalar
Test-Driven Development, Red-Green-Refactor, Unit testing, Refactoring, Test first, Regression testing, Characterization test, Mock, Clean code, Test automation