Testlash o'zi nimaga kerak, tinchgina yashasak bo'lmaydimi!

humoyun

Humoyun Ahmad

Posted on March 21, 2023

Testlash o'zi nimaga kerak, tinchgina yashasak bo'lmaydimi!

Bismillah!

Taxminiy o'qish vaqti: ~5 daqiqa

Assalom Alaykum!

O'tgan qismimizda asosan frontend dagi relizgacha bo'lgan barcha jarayonlarni umumlashtirilgan shaklda ko'rib chiqdik. Bu va bundan keyingi qismlarda dastlabki maqolada keltirilgan mavzularga kengroq kiramiz va ularni qanday oddiy setup qilishlikni ko'rib chiqamiz. Bugun shu mavzularga kirish qismi qilamiz!

Ushbu turkum maqolalarda ishlatilgan barcha kodlarni quyidagi github repodan topishingiz mumkin: testing-demo-app. Alohida repodan asosiy maqsad ham bu mavzularni iloji boricha amaliy ko'rinishga keltirishdir.

React Testing Demo App

This repo is developed for showing how to setup all necessary modern tooling and good practices for development and bootstrap tests with React (both Jest and Cypress)

Available Scripts

In the project directory, you can run:

  • yarn install: run this after cloning project to install all necessary dependencies

  • yarn postinstall: run this to setup pre-commit

  • yarn start: run this to start an app

  • yarn test: run this to run all tests

  • yarn start:msw: run this to start app in mocking mode

  • yarn cy:open: run this to open Cypress in UI mode

  • yarn cy:run: run this to open Cypress in headless mode

  • npm run build:

Extra steps

Need to setup relative path resolving using tspath as tsconfig baseUrl is only helpful on compile time, in order to resolve after it is transpiled into JS it cannot resolve TS configs…

Testlash o'zi nimaga kerak, tinchgina yashasak bo'lmaydimi!

Spoiler: Ground truth of testing is the confidence! 😊

Hozirgi kunda sifatli dasturiy ta'minotni ishlab chiqish jarayonini testlarsiz tasavvur qilish qiyin. Yozayotgan kodimiz doimo to'g'ri ishlashiga ishonch hosil qilishimiz uchun albatta ularni testlar bilan himoyalab qo'yishimiz lozim. Chunki tabiatan har qanday dasturiy ta'minot vaqt o'tishi bilan o'zgarishlarga mahkum va har qanday o'zgarishlardan keyin ham uning to'g'ri ishlayotganiga ishonch hosil qilishimiz uchun ham testlarni yozamiz. Ho'p test yozish muhim ekan lekin ularni qanday yozamiz, ularning qanday turlari bor, ularni yozishda qandaydir usullar, qonun qoidalar ham bormi... Shu va shunga o'xshash savollar test yozishni yangi boshlayotganlarda bo'lishi tabiiy. Keling shular haqida biroz gaplashamiz.

Little story: Esimda, bundan taxminan 3 yilcha oldin Agoda bilan bo'lgan intervyumda Agodani senior engineeri mendan: hozirgi ishxonangda testlarni qanday yozaslar deb soragandi. Uhh dedim ichimda, xo'sh testlar yozish nimaligini bilaman, ahamiyatini ham, o'zimcha bir nechta test yozib ko'rganman, lekin baribir ishxonamda yozmaymizku. Aldashni keragi yo'q, deb to'g'risini aytdim. Bizda test yozilmaydi, chunki startup bo'lganimiz uchun vaqtimiz kam (oo ajoyib bahona keltirdim deb o'yladim ichimda). U esa menga kulib, bizni ham vaqtimiz kam, vaqtimiz yana ham kamaymasligi uchun test yozamiz deb javob berdi. Shu suhbatdan keyingina, testlarning haqiqiy ahamiyatini tushundim (shekilli?).

Har qanday ishga tizimli tarzda yondashish doimo yaxshi natija beradi. Testlarni yozishda bunday tizimli yondashuv odatda testlash strategiyasi deb nomlangan bo'lib ular turli test turlarini qanday kombinatsiyalarda bo'lishini muayyan bir qolipga solib tashkillashtirishni anglatadi. Dasturchilar orasida ko'p tarqalgan bunday strategiyalardan biri bu Testing Pyramiddir. Unga ko'ra UI testlar (ba'zida e2e testlar nazarda tutiladi) bu eng qimmat, eng ko'p vaqt talab qiladigan va eng sekin ishlaydigan testlardir, unit testlar esa aksincha eng tez va eng oson yoziladigan, kam mashaqqat talab qiladigan jarayondir.

Unit testlar bu dastur kodining eng kichik va o'zi mustaqil biron amal bajara oladigan bo'lagini testlaydi xuddi funksiya yoki React component kabi. Ularni run qilishimiz uchun bizga browser, server yoki database kerak emas shuning uchun ularni ishlashi juda tez.
UI testlarni (odatda e2e nazarda tutiladi) run qilish uchun esa butun boshli dasturni browserda ishga tushirish kerak bo'ladi, odatda haqiqiy server va database bilan birgalikda, so'ngra esa bu testlar hosil qilgan trash datani tozalalashimiz (o'chirish) kerak. Yuqorida ham aytib o'tilganidek, bu ko'p vaqt oladigan jarayon, va ularni yozish ancha mashaqqatliroq.
Integration testlar esa (service yoki funksional deb ham nomlanadi ba'zida) bu ikki turdagi testlarni orasida joylashgan. Ular dasturning bir nechta o'zaro bo'gliq qismlarini tekshiradi lekin browsersiz va odatda haqiqiy serversiz.

Demak biz ko'plab unit testlar va birozgina UI testlar yozishimiz kerak, shundaymi?

Bu uslub sinalgan va ishlaydigan strategiya bo'lishiga qaramay, frontendga qo'llashda o'ziga yarasha kamchiliklari ham bor, bundan tashqari bu strategiya tanishtirilgan vaqtni ham hisobga olish juda muhim. Ajax revolyutsiyasidan oldin JavaScript odatda formalarni validatsiya qilish va sodda animatsiyalarni hosil qilish kabi oddiy amaliyotlar uchungina ishlatilalardi va u paytlari testing uchun ayniqsa frontendda testlar yozish uchun vositalar kam va imkoniyatlari cheklangan bo'lishiga qaramay o'sha vaqtdagi talab va ehtiyojlariga javob bera olardi. Lekin so'nggi 10 yillikda web va uning atrofidagi texnologiyalarning soni va imkoniyatlari ancha kengaydi bu esa frontendning ancha murakkablashuviga olib keldi. SPA ya'ni client-side routing, client-side state management va client-side rendering kabi texnologiyalar va bular atrofidagi juda ko'plab frameworklar va librarylar web dasturlash olamiga kirib keldi va testlashdagi oldingi usullar, texnologiyalar va vositalar hozirgi kun frontenddagi testlash talablarini va ehtiyojlarini to'liq qondira olmay qoldi. Bunga yana quyidagi sabablarni ham ko'rsatish mumkin:

  • frontend da UI doimiy o'zgarishda (funksional hech narsa o'zgarmasa ham), bu esa ko'p yozilgan unit testlarni fail bo'lishiga olib kelaveradi va har doim biron styling bilan bog'liq o'zgarish qilganimizda unit testlarni o'zgartirishimizga to'g'ri keladi.
  • unit testlar qanchalik ko'p bo'lmasin va barchasi muvaffaqiyatli ishlamasin agar ular tasdiqlab bergan dasturning qismlari birgalikda to'g'ri ishlamasa unda ulardan katta naf bo'lmaydi. Buning muqobilida, agar bu qismlar birgalikda to'g'ri ishlasa unda juda ko'p unit testlarni yozishga ham hojat qolmaydi. Chunki shuning o'zi dasturning imkoniyatlari to'g'ri ishlayotgani haqida bizga yetarli confidence ya'ni ishonch darajasini bera oladi.

Balki frontendda test yozishda sal boshqacharoq yondashuv kerakdir?

Frontendda testlashning zamonaviy strategiyalardan biri bu Testing Trophy.

Modern Testing Trophy Standard Testing Pyramid
testing-trophy-by-kent-c-dodds standard-testing-pyramid

Testing Trophy πŸ†

Bu strategiya ko'ra eng katta ROI (return on investment) bu integration testlarda.

ROI - sarflangan xarajat yoki mashaqqatlarga nisbatan keltirilgan natija yoki foyda.

Integration testlar dasturning muayyan imkoniyatlarini (feature) yoki butun boshli sahifani to'liq tekshiradi lekin odatda haqiqiy backend va databasega ulanmagan holatda. Masalan, quyidagi auth flow ni misol qilib olishimiz mumkin (Login sahifasini):

  1. Login sahifamizni render qilamiz (oldinlari odatda browsersiz JSDOM kabi headless runtimeda edi hozir esa Cypress kabi zamonaviy testlash vositalari yordamida to'g'ridan to'g'ri browserni o'zida ham render qilsa bo'ladi)
  2. username va password input elementlarini topamiz va kerakli test user credentiallarni kirgazamiz.
  3. Sign In buttonni topamiz va Click.
  4. To'g'ri request yuborilganini tekshiramiz.
  5. Oxirgi bosqich holatga qarab har xil, misol uchun:
    • Login sahifasidan dasturning asosiy qismiga redirect qilinganligi va biron textning asosiy sahifada borligini tekshirish yoki...
    • SessionId yoki JWT token ni cookie yoki localStoragega yozilganligini tekshiramiz yoki...
    • va hokazo

Lekin bu jarayonda network requestlar serverga yetib bormaydi va msw kabi vositalar yordamida bu requestlar intercept qilinib mock natijalar qaytariladi bunga keyinroq to'liqroq misol bilan to'xtalamiz.

Keling endi unit va integration testlarni solishtiramiz:

Unit testlar Integration testlar
  • bitta test faqat bitta kichik dastur qisminigina qoplay oladi (e.g. funksiya yoki component)
  • odatda har bir refactoringdan keyin o'zgartirishga to'g'ri keladi.
  • odatda implementation detallaridan holi tarzda testlash qiyin ya'ni testdagi ketma-ketliklar foydalanuvchilarning dasturni ishlatishdagi ketma-ketliklariga mos tushmaydi
  • LOW confidence. πŸ’§
  • bitta test butun boshli userflow, featureni yoki hatto sahifani ham qoplaydi.
  • odatda refactoringdan o'zgarishsiz chiqadi
  • implementation detallaridan deyarli holi va foydalanuvchilar dasturni ishlatishidagi ketma ketliklarni yaxshi aks ettiradi
  • HIGHER confidence. πŸ’ͺ

Oxirgi farq bu yerda eng muhim jihatlardan biridir ya'ni turli testlar beradigan turli ishonch darajalari (level of confidence)! Integration testlar bizga dasturiy ta'minotimiz kutilganidek ishlayotganiga yetarli darajada ishonch bera oladi. Bu qolgan testlarni yozish kerak emas degani ham emas, shunchaki asosiy vaqt va e'tiborni integration testlarga berish bizga yaxshi natija olib keladi.

user flow - dasturda muayyan natijaga foydalanuvchi qanday erishishini ko'rsatuvchi ketma-ketlikdir (e-commerce appda muayyan mahsulotni topish, uni korzinkaga qo'shish va checkout qilish).

implementatsiya detallari - dasturimizning ichki ishlash mexanizmi bo'lib foydalanuvchilarga ko'rinmaydi va dasturning spesifikatsiyasida ham ko'rsatilmaydi. Dasturchini ishlashi jarayonida hosil bo'lib boradi va odatda vaqt o'tishi bilan o'zgarishlarga mahkum.

Quyida integration testlarni muhimroq ekanligi haqida keltirilgan ajoyib xazilomuz gif (original tweet muallifi Erin McGrath)

expect(umbrellaOpens).toBe(true)

tests: 1 passed, 1 total

**all unit tests passed, hooray**
Enter fullscreen mode Exit fullscreen mode

all tests passed

Demak xulosa:

write mostly integration tests

Xo'sh testlash, testlarning turlari va testlash strategiyasi haqida bilib oldik va Testing Trophy strategiyasini frontend uchun tanlab oldik. Keyingi maqolalarda ularning har bir qatlami bilan alohida alohida tanishib chiqamiz.

πŸ’– πŸ’ͺ πŸ™… 🚩
humoyun
Humoyun Ahmad

Posted on March 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related