Azimjon Abdurasulov

QA 13: Terminal, Git, Docker va Loglar — QA'ning muhandislik asboblari

🧪 QA Engineer — Zero to Hero

QA 13: Terminal, Git, Docker va Loglar — QA'ning muhandislik asboblari

Holat: 2026-yil oktabr. Terminal va Git misollari macOS 26 (zsh) va Git 2.53 da ishga tushirib tekshirilgan — git bisect, grep, curl va jq chiqishlari haqiqiy. Docker Compose buyruqlari Docker'ning rasmiy hujjatlari asosida keltirilgan.

Bu darsdan keyin siz: dasturchi bilan bir tilda gaplashadigan "texnik QA"ga aylanasiz.

  • terminalda fayl, log va API bilan tez ishlaysiz (grep, tail -f, curl, jq);
  • feature branch'ni lokal ishga tushirib test qilasiz va PR'ni QA ko'zi bilan o'qiysiz;
  • git bisect bilan regressiyani keltirib chiqargan commit'ni bir necha qadamda topasiz;
  • Docker Compose bilan lokal muhitni ko'tarasiz, loglarini o'qiysiz va tozalaysiz;
  • log, request ID va stack trace'dan bug report uchun dalil yig'asiz.

Mundarija

  1. Nega QA'ga terminal kerak
  2. Terminal asoslari: navigatsiya va fayllar
  3. grep, pipe va yo'naltirish: loglarda qidirish
  4. curl va jq: API bilan terminaldan ishlash
  5. O'zgaruvchilar va skriptlar: mini smoke test
  6. Git QA uchun: branch, log, diff, blame, stash
  7. git bisect: regressiyani topish
  8. Muhitlar, feature flag'lar va .env
  9. Docker va Docker Compose: lokal muhit
  10. Loglar: darajalar, structured log, request ID
  11. Stack trace va mobil loglar
  12. Amaliy mashqlar
  13. Xulosa
  14. Manbalar

1. Nega QA'ga terminal kerak {#nega-terminal}

Ko'p yangi QA'lar terminaldan qo'rqadi: qora ekran, hech qanday tugma yo'q. Lekin amalda u — eng tez "pult". Bir qator buyruq bilan 10 000 qatorlik logdan kerakli xatoni topasiz, API'ni brauzersiz chaqirasiz yoki dasturchining branch'ini o'z kompyuteringizda ishga tushirasiz.

VaziyatTerminalsizTerminal bilan
Server logida bitta so'rov izini topishFaylni ochib, ko'z bilan qidirishgrep "req-7f3a" api.log
API javob beryaptimiPostman ochish, so'rov yasashcurl -s -o /dev/null -w "%{http_code}" URL
Dasturchi "fix qildim" dedi — lekin qaysi branch'da?Kutish, so'rashgit switch feature/... yoki gh pr checkout 123
"Qachondan buzildi?"Taxmingit bisect bilan aniq commit
Lokal muhitni noldan ko'tarishKo'rsatma bo'yicha soatlab sozlashdocker compose up -d

Bu dars dasturchi bo'lishni talab qilmaydi. Maqsad — QA ishida eng ko'p uchraydigan 20–30 ta buyruqni ishonch bilan ishlatish.

🎯 Intervyuda: "Log fayldan ma'lum foydalanuvchi so'rovlarini qanday topasiz?" — grep bilan request ID yoki user ID bo'yicha qidiraman (grep -n "req-7f3a" api.log), kontekst uchun -C 2, real vaqtda kuzatish uchun tail -f api.log | grep ERROR. Structured (JSON) log bo'lsa — jq 'select(.requestId == "req-7f3a")'.


2. Terminal asoslari: navigatsiya va fayllar {#terminal-asoslari}

Qayerda ishlaymiz:

OSTerminalShell
macOSTerminal.app yoki iTerm2zsh (macOS 10.15 dan beri default; undan oldin bash)
LinuxIstalgan terminalKo'pincha bash
WindowsWindows TerminalPowerShell; Linux buyruqlari uchun WSL tavsiya etiladi

Bu darsdagi buyruqlar macOS, Linux va WSL'da ishlaydi. Windows PowerShell'da sintaksis farq qiladi.

Eng kerakli buyruqlar

BuyruqNima qiladiMisol
pwdHozir qaysi papkadamanpwd
ls -laPapka ichidagilar (yashirin fayllar bilan)ls -la logs/
cdPapkaga o'tishcd ~/projects/demobozor, cd ..
mkdir -pPapka yaratish (ichma-ich ham)mkdir -p evidence/BUG-1234
cp, mvNusxa olish, ko'chirish/qayta nomlashcp api.log api.backup.log
catFaylni to'liq chiqarishcat version.json
lessKatta faylni varaqlab o'qish (/ qidirish, q chiqish)less api.log
head -n, tail -nBoshidan / oxiridan N qatortail -n 50 api.log
tail -fFaylga yozilayotganlarni real vaqtda kuzatish (Ctrl+C to'xtatadi)tail -f api.log
wc -lQatorlar soniwc -l api.log
findFayl qidirishfind . -name "*.log" -mtime -1 (oxirgi 1 kunda o'zgargan)

Vaqtni tejaydigan odatlar: Tab — nomni avtomatik to'ldiradi; ↑ — oldingi buyruq; Ctrl+R — tarixdan qidirish; Ctrl+C — ishlayotgan buyruqni to'xtatish; clear — ekranni tozalash.

⚠️ Diqqat: rm faylni Savatga emas, butunlay o'chiradi, rm -rf papka esa butun papkani so'roqsiz yo'q qiladi. Buyruqni boshqa joydan ko'chirib olganda, rm bilan boshlansa — Enter bosishdan oldin ikki marta o'qing.


3. grep, pipe va yo'naltirish: loglarda qidirish {#grep-pipe}

Mashq uchun DemoBozor API'ning (xayoliy) log fayli. Quyidagi buyruq faylni yaratadi — <<'EOF' dan EOF gacha bo'lgan matn faylga yoziladi:

cat > api.log <<'EOF'
2026-10-08T16:25:01.112Z INFO  [req-5a1c] POST /api/v1/orders user=9 status=201 ms=184
2026-10-08T16:25:03.540Z INFO  [req-5a1d] GET /api/v1/products?query=choynak status=200 ms=42
2026-10-08T16:26:00.020Z WARN  [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
2026-10-08T16:26:05.300Z INFO  [req-5a1e] GET /api/v1/cart user=3 status=200 ms=37
2026-10-08T16:28:30.004Z INFO  [req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000
2026-10-08T16:30:12.777Z INFO  [req-5a1f] GET /api/v1/orders/11 user=9 status=200 ms=29
2026-10-08T16:31:40.101Z WARN  [req-5a20] POST /api/v1/auth/verify phone=+99890***4567 attempts=3 status=429
2026-10-08T16:31:41.500Z INFO  [req-5a21] GET /api/v1/products?query=gilam status=200 ms=51
EOF

grep — matn bo'yicha qidirish

$ grep -n "ERROR" api.log
4:2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
7:2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000

$ grep -c "ERROR" api.log
2

$ grep "req-7f3a" api.log
2026-10-08T16:26:00.020Z WARN  [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"

$ grep -E "status=5[0-9]{2}" api.log
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
FlagMa'nosiQachon kerak
-nQator raqamini ko'rsatadiBug report'da aniq joyga ishora qilish
-cFaqat sonini chiqaradi"Nechta xato bor?"
-iKatta-kichik harfni farqlamaydierror, Error, ERROR hammasi
-vTeskari: mos kelmagan qatorlargrep -v INFO — shovqinni olib tashlash
-EKengaytirilgan regexstatus=5[0-9]{2} — barcha 5xx
-oFaqat mos kelgan qismni chiqaradiStatistika yig'ish
-C 2, -A, -BAtrofdagi qatorlar (context, after, before)Xatodan oldin nima bo'ldi?
-rPapka ichida rekursivgrep -rn "FREE_DELIVERY" src/
-wButun so'z-w 200 — 2001 ga mos kelmaydi

Pipe (|) — buyruqlarni zanjir qilish

Pipe bir buyruq chiqishini keyingisiga kirish qilib beradi. Status kodlar statistikasi bir qatorda:

$ grep -o "status=[0-9]*" api.log | sort | uniq -c | sort -rn
   4 status=200
   2 status=201
   1 status=502
   1 status=429

$ grep -v "INFO" api.log | wc -l
       4

O'qish tartibi: status'larni ajratib ol → saralab qo'y → bir xillarini sanab chiqar → sanoq bo'yicha kamayish tartibida sarala.

Yo'naltirish: dalilni faylga saqlash

grep "req-7f3a" api.log > evidence-BUG-1234.txt    # > — fayl yaratadi yoki USTIDAN yozadi
grep "req-7f3b" api.log >> evidence-BUG-1234.txt   # >> — oxiriga qo'shadi
some-command 2>&1 | tee run.log                    # xatolarni ham ushlab, ekranga va faylga

⚠️ Diqqat: > mavjud faylni so'roqsiz qayta yozadi. Muhim logni > bilan "ustidan" yozib yubormang — qo'shish uchun >>.

Real vaqtda kuzatish

tail -f api.log | grep --line-buffered "ERROR"

Ilovada amal bajarasiz — terminalda xato darhol paydo bo'ladi. Ctrl+C bilan to'xtatiladi. Bu "qaysi bosish qaysi xatoni keltirib chiqardi" degan savolga eng tez javob.

macOS (BSD) va Linux (GNU) farqlari

macOS'dagi ko'p buyruqlar BSD versiyasi, Linux'da esa GNU. Internetdagi misollar ko'pincha GNU uchun yozilgan:

VazifaLinux (GNU)macOS (BSD)
Perl regexgrep -P "\d+"/usr/bin/grep -P'ni qo'llamaydi → grep -E "[0-9]+"
Faylni joyida tahrirlashsed -i 's/a/b/' f.txtsed -i '' 's/a/b/' f.txt
Kechagi sanadate -d yesterday +%Fdate -v-1d +%F
Versiyani ko'rishsed --versionKo'p BSD vositalarida --version yo'q

Biror buyruq macOS'da "illegal option" desa — birinchi gumon shu farq.


4. curl va jq: API bilan terminaldan ishlash {#curl-jq}

curl — HTTP so'rov yuboradi, jq — JSON javobni filtrlaydi va chiroyli ko'rsatadi. jq odatda alohida o'rnatiladi: macOS'da brew install jq, Debian/Ubuntu'da sudo apt-get install jq, Windows'da winget install jqlang.jq.

$ curl -s https://jsonplaceholder.typicode.com/todos/1 | jq .
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

$ curl -s -o /dev/null -w "%{http_code}\n" https://restful-booker.herokuapp.com/ping
201

$ curl -s -X POST https://restful-booker.herokuapp.com/auth \
    -H "Content-Type: application/json" \
    -d '{"username":"admin","password":"password123"}' | jq -r .token
e8dcaccbe7170f4

$ curl -s https://jsonplaceholder.typicode.com/users | jq -r '.[] | "\(.id)\t\(.email)"' | head -3
1	Sincere@april.biz
2	Shanna@melissa.tv
3	Nathan@yesenia.net

Token har safar boshqacha bo'ladi — sizdagi qiymat farq qiladi.

curl flagMa'nosi
-sJim rejim (progress chiqmaydi)
-iJavob header'larini ham ko'rsatadi
-X POSTHTTP metod
-H "..."Header qo'shish
-d '...'So'rov tanasi (body)
-o /dev/null -w "%{http_code}"Tanani tashlab, faqat status kodni chiqarish
--max-time 1010 soniyadan oshsa to'xtatish
jq ifodaMa'nosi
.Butun JSON, chiroyli formatda
.title, .data.idMaydon qiymati
-rQo'shtirnoqsiz "xom" matn
lengthMassiv uzunligi / obyekt maydonlari soni
.[]Massiv elementlari bo'ylab
select(.level == "error")Shartga mos elementlar

QA topilmasi: "200 OK" ichidagi xato

$ curl -s -o /dev/null -w "%{http_code}\n" -X POST https://restful-booker.herokuapp.com/auth \
    -H "Content-Type: application/json" -d '{"username":"admin","password":"xato"}'
200
$ curl -s -X POST https://restful-booker.herokuapp.com/auth \
    -H "Content-Type: application/json" -d '{"username":"admin","password":"xato"}'
{"reason":"Bad credentials"}

Noto'g'ri parol — lekin status 200. REST odatlariga ko'ra bu 401 Unauthorized bo'lishi kerak edi. Faqat status kodga qaraydigan avtotest bu holatni "muvaffaqiyatli login" deb o'tkazib yuboradi. Restful-booker o'quv maqsadida atayin "xato" qilingan API — real loyihada bu bug report bo'lardi (QA 11).

💡 Maslahat: Chrome DevTools'dagi va Proxyman'dagi Copy as cURL funksiyasi brauzer yoki mobil ilova yuborgan so'rovni aynan terminal buyrug'i ko'rinishida beradi (QA 9, QA 15). Uni bug report'ga qo'shsangiz, dasturchi muammoni bir buyruq bilan takrorlaydi. Faqat ichidagi token va shaxsiy ma'lumotlarni yashirishni unutmang.


5. O'zgaruvchilar va skriptlar: mini smoke test {#skriptlar}

Environment variable — buyruqlar va dasturlar o'qiydigan nomlangan qiymat:

export BASE_URL=https://staging.demobozor.example   # joriy terminal sessiyasi uchun
echo $BASE_URL
env | grep BASE_URL
BASE_URL=http://localhost:3001 ./smoke.sh          # faqat shu bitta buyruq uchun

Endi takrorlanadigan tekshiruvni skriptga aylantiramiz. smoke.sh — muhim endpoint'lar kutilgan status kodni qaytarayotganini tekshiradi:

#!/usr/bin/env bash
# smoke.sh — muhim endpoint'lar javob beryaptimi? (QA uchun mini smoke)
set -u
BASE_URL="${BASE_URL:-https://restful-booker.herokuapp.com}"
failed=0

check() {
  local path="$1" expected="$2"
  local code
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$BASE_URL$path")
  if [ "$code" = "$expected" ]; then
    echo "✅ $path → $code"
  else
    echo "❌ $path → $code (kutilgan: $expected)"
    failed=$((failed + 1))
  fi
}

check "/ping" 201
check "/booking" 200
check "/booking/0" 404

if [ "$failed" -gt 0 ]; then
  echo "Smoke FAILED: $failed ta tekshiruv yiqildi"
  exit 1
fi
echo "Smoke PASSED"
$ chmod +x smoke.sh
$ ./smoke.sh
✅ /ping → 201
✅ /booking → 200
✅ /booking/0 → 404
Smoke PASSED
$ echo $?
0

$ BASE_URL=https://jsonplaceholder.typicode.com ./smoke.sh
❌ /ping → 404 (kutilgan: 201)
❌ /booking → 404 (kutilgan: 200)
✅ /booking/0 → 404
Smoke FAILED: 2 ta tekshiruv yiqildi
$ echo $?
1

Muhim tafsilotlar:

  • #!/usr/bin/env bash (shebang) — faylni qaysi dastur bajarishini aytadi; chmod +x uni ishga tushiriladigan qiladi.
  • ${BASE_URL:-...} — o'zgaruvchi berilmasa, default qiymat.
  • Exit code: 0 — muvaffaqiyat, 0 dan boshqasi — xato. $? oxirgi buyruqning exit code'ini ko'rsatadi. CI tizimlari aynan shunga qarab pipeline'ni "qizil" yoki "yashil" qiladi (QA 21).

6. Git QA uchun: branch, log, diff, blame, stash {#git}

Git — kod tarixini saqlaydigan tizim. QA uchun u "vaqt mashinasi": istalgan versiyani ishga tushirish, nima o'zgarganini ko'rish, xato qachon paydo bo'lganini topish. To'liq asoslar: Git for iOS Developers va Git buyruqlari cheat sheet.

TushunchaQA uchun ma'nosi
Repository (repo)Loyiha va uning butun tarixi
CommitBitta saqlangan o'zgarish (hash, muallif, sana, xabar)
BranchParallel ish chizig'i: main, feature/promo-code-v2
Pull Request (PR) / Merge Request"Mening branch'imni main'ga qo'shing" degan so'rov + review
TagReliz belgisi: v1.2, v1.3

Dasturchining branch'ini test qilish

git clone https://github.com/<org>/demobozor.git   # bir marta
cd demobozor
git fetch origin                                    # yangi branch'larni olib kelish
git switch feature/promo-code-v2                    # branch'ga o'tish
git pull                                            # eng so'nggi commit'lar
gh pr checkout 123                                  # GitHub CLI: PR raqami bo'yicha (gh o'rnatilgan bo'lsa)

Nima o'zgardi? Reliz orasidagi farq

Regression testing ko'lamini tanlashning eng aniq usuli — ikki reliz orasidagi commit'lar va fayllarga qarash. Quyidagi chiqishlar 7-bo'limdagi mashq repo'sidan:

$ git log --oneline v1.2..v1.3
d0634b0 versiya 1.3.0
5532ddd README yangilandi
1257f6b magic number'lar konstantaga chiqarildi
4bfe1f8 viloyatlar uchun yetkazish muddati

$ git diff --stat v1.2 v1.3
 README.md    | 1 +
 delivery.mjs | 9 ++++++++-
 version.json | 1 +
 3 files changed, 10 insertions(+), 1 deletion(-)

delivery.mjs o'zgargan — demak yetkazish narxi va muddati regression ro'yxatida birinchi o'rinda. "Refactor" so'zi aldamasin: "faqat kodni chiroyli qildim" degan commit'lar ham xatti-harakatni o'zgartirib yuborishi mumkin.

Kim, qachon, nima uchun: blame va pickaxe

$ git blame -L 4,7 delivery.mjs
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 4) export function deliveryFee(subtotal, isPremium = false) {
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 5)   if (isPremium) return 0;
1257f6b2 (QA Demo 2026-10-09 22:14:44 +0500 6)   return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 7) }

$ git log -S "FREE_DELIVERY_THRESHOLD" --oneline
1257f6b magic number'lar konstantaga chiqarildi

git blame har bir qatorni oxirgi o'zgartirgan commit'ni ko'rsatadi. git log -S "matn" esa shu matn qo'shilgan yoki olib tashlangan commit'larni topadi. Maqsad aybdor qidirish emas — kontekst: o'sha commit'ning PR'i va tiketini o'qib, o'zgarish sababini bilib olasiz.

Yarim ishni vaqtincha chetga qo'yish: stash

$ git stash -u          # o'zgarishlar (yangi fayllar bilan) vaqtincha saqlanadi
Saved working directory and index state WIP on feature/qa-test: 0cd74b8 versiya 1.3.0
$ git stash list
stash@{0}: WIP on feature/qa-test: 0cd74b8 versiya 1.3.0
$ git switch main       # toza holatda boshqa branch'ga o'tasiz
$ git stash pop         # qaytib kelib, saqlanganini tiklaysiz

PR'ni QA ko'zi bilan o'qish

Nimaga qarashNega
Bog'langan tiket va qabul mezonlariNimani test qilish kerakligi shu yerda
O'zgargan fayllar ro'yxatiRisk zonalari va regression ko'lami
Testlar qo'shilganmi / o'zgarganmiAvtomat qamrov bormi
Migratsiyalar (DB sxema)Ma'lumotga ta'sir, rollback xavfi
Konfiguratsiya, feature flag'larIkkala holatni ham test qilish kerak
CI natijasiQizil CI bilan qo'lda test boshlamang
Skrinshot / videoUI o'zgarishini kutilgan dizayn bilan solishtirish

⚠️ Diqqat: git reset --hard, git clean -fd, git checkout -- . saqlanmagan o'zgarishlarni qaytarib bo'lmas tarzda o'chiradi. QA sifatida ular deyarli kerak bo'lmaydi; ishlatishdan oldin git status bilan nima yo'qolishini ko'ring yoki git stash qiling.


7. git bisect: regressiyani topish {#git-bisect}

Ssenariy. DemoBozor v1.2 da 300 000 so'mlik buyurtmaga yetkazish bepul edi. v1.3 da xaridorlar 20 000 so'm to'layapti. Ikki reliz orasida o'nlab commit bo'lishi mumkin — qaysi biri buzdi?

git bisect binary search qiladi: "yaxshi" va "yomon" commit orasini har safar teng ikkiga bo'ladi. 1000 ta commit orasidan aybdorni taxminan 10 ta tekshiruvda topadi.

Git oqimi va QA nuqtalari: branch, PR, CI, staging, merge, reliz va bisect

Mashq repo'sini yaratish

Quyidagi skript 6 ta commit'li kichik repo yaratadi (sizdagi commit hash'lari boshqacha bo'ladi — bu normal):

#!/usr/bin/env bash
# bisect-demo.sh — git bisect mashqi uchun kichik repo yaratadi
set -euo pipefail
mkdir delivery-demo && cd delivery-demo
git init -q -b main
git config user.name "QA Demo"
git config user.email "qa-demo@example.com"

fee_v1='export function deliveryFee(subtotal, isPremium = false) {
  if (isPremium) return 0;
  return subtotal >= 300000 ? 0 : 20000;
}'
fee_v2='const FREE_DELIVERY_THRESHOLD = 300000;
const DELIVERY_FEE = 20000;

export function deliveryFee(subtotal, isPremium = false) {
  if (isPremium) return 0;
  return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;
}'
days='export function deliveryDays(region) {
  return region === "Toshkent" ? 1 : 4;
}'

commit() { git add -A && git commit -q -m "$1"; }

echo "$fee_v1" > delivery.mjs;                         commit "premium mijozlar uchun bepul yetkazish"
echo "# DemoBozor delivery" > README.md;               commit "README qo'shildi"; git tag v1.2
printf '%s\n\n%s\n' "$fee_v1" "$days" > delivery.mjs; commit "viloyatlar uchun yetkazish muddati"
printf '%s\n\n%s\n' "$fee_v2" "$days" > delivery.mjs; commit "magic number'lar konstantaga chiqarildi"
echo "Narxlar so'mda." >> README.md;                   commit "README yangilandi"
echo '{ "version": "1.3.0" }' > version.json;          commit "versiya 1.3.0"; git tag v1.3
git log --oneline --decorate

Va QA tekshiruvi — repo'dan tashqarida turadigan qa-check.mjs (Node.js kerak):

// QA tekshiruvi: 300 000 so'mlik buyurtmada yetkazish bepul bo'lishi kerak
import { pathToFileURL } from "node:url";

const { deliveryFee } = await import(
  pathToFileURL(`${process.cwd()}/delivery.mjs`).href
);
const fee = deliveryFee(300000);
console.log(`deliveryFee(300000) = ${fee}`);
process.exit(fee === 0 ? 0 : 1); // 0 = good, 1 = bad
bash bisect-demo.sh        # repo yaratiladi
cd delivery-demo

Qo'lda bisect

$ git bisect start
status: waiting for both good and bad commits
$ git bisect bad                 # hozirgi HEAD (v1.3) — buzuq
status: waiting for good commit(s), bad commit known
$ git bisect good v1.2           # v1.2 — ishlagan
Bisecting: 1 revision left to test after this (roughly 1 step)
[1257f6b2802163502533eb65a89c3a40712cf956] magic number'lar konstantaga chiqarildi
$ node ../qa-check.mjs
deliveryFee(300000) = 20000
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[4bfe1f8f9989f70abf85a147ddd6afddb727bb6c] viloyatlar uchun yetkazish muddati
$ node ../qa-check.mjs
deliveryFee(300000) = 0
$ git bisect good
1257f6b2802163502533eb65a89c3a40712cf956 is the first bad commit
commit 1257f6b2802163502533eb65a89c3a40712cf956
Author: QA Demo <qa-demo@example.com>

    magic number'lar konstantaga chiqarildi

 delivery.mjs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
$ git bisect reset               # bisect tugadi, main'ga qaytamiz

Har qadamda git sizga bitta commit'ni "checkout" qiladi; siz test qilib good yoki bad deysiz. Real loyihada "test" — ilovani ishga tushirib, qo'lda tekshirish ham bo'lishi mumkin.

Avtomatik bisect: git bisect run

Tekshiruv skript bo'lsa, butun jarayonni git'ning o'zi bajaradi:

$ git bisect start v1.3 v1.2     # avval "bad", keyin "good"
$ git bisect run node ../qa-check.mjs
running 'node' '../qa-check.mjs'
deliveryFee(300000) = 20000
Bisecting: 0 revisions left to test after this (roughly 0 steps)
running 'node' '../qa-check.mjs'
deliveryFee(300000) = 0
1257f6b2802163502533eb65a89c3a40712cf956 is the first bad commit
...
bisect found first bad commit
$ git bisect reset

Skriptning exit code'i git uchun hukm:

Exit codeMa'nosi
0good — bu commit'da xato yo'q
1–127 (125 dan tashqari)bad — xato bor
125bu commit'ni test qilib bo'lmaydi (masalan, build bo'lmaydi) — o'tkazib yuboriladi
boshqalarbisect to'xtatiladi

Aybdor commit'ning diff'i hamma narsani aytadi:

-  return subtotal >= 300000 ? 0 : 20000;
+  return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;

"Faqat magic number'larni konstantaga chiqarish" vaqtida >= jimgina > ga aylangan. Bug report'ga "Regression v1.3: 1257f6b commit'da kiritilgan, deliveryFee ichida >= → >" deb yozsangiz, dasturchi tuzatishni minutlarda qiladi. Shu xato SQL darsida ma'lumotlar bazasida ham ko'ringan edi (QA 12) — 4-buyurtma.

🎯 Intervyuda: "Regressiya qaysi commit'da paydo bo'lganini qanday topasiz?" — Ishlagan versiya (masalan, oldingi reliz tag'i) va buzilgan versiyani aniqlab, git bisect bilan binary search qilaman; tekshiruvni skriptga aylantira olsam — git bisect run. Natijada aybdor commit, uning PR'i va tiketini bug report'ga qo'shaman.


8. Muhitlar, feature flag'lar va .env {#muhitlar}

Bitta ilova bir nechta muhitda (environment) yashaydi:

MuhitKim ishlatadiMa'lumotQA nima qiladi
LocalDasturchi, QA o'z kompyuteridaSun'iy, istalgancha buzish mumkinFeature branch'ni tekshirish, eksperiment
DevJamoa, har merge'dan keyinSun'iyTez tekshiruv, integratsiya
Staging / QAQA jamoasiProd'ga yaqin, anonimlashtirilganAsosiy testlash, regression
Pre-prod / UATBiznes, mijozProd nusxasiQabul testlari (acceptance)
ProductionHaqiqiy foydalanuvchilarHaqiqiySmoke, monitoring, faqat o'qish

Feature flag'lar

Feature flag — funksiyani kodni qayta deploy qilmasdan yoqib-o'chirish imkoniyati. Masalan, promo_v2_enabled. QA uchun qoida: flag bilan yopilgan funksiyani ikkala holatda ham test qiling — yoqilganda ishlashi va o'chirilganda eski oqim buzilmagani. Bir nechta flag bo'lsa, ularning kombinatsiyalari ham risk.

Konfiguratsiya va .env

Ilova sozlamalarini (API manzili, kalitlar, log darajasi) koddan tashqarida, environment variable'larda saqlash — keng tarqalgan amaliyot ("The Twelve-Factor App" metodologiyasi). Lokal ishlab chiqishda ular odatda .env faylda turadi:

# .env.example — repo'da saqlanadi, haqiqiy qiymatlarsiz
BASE_URL=http://localhost:3001
API_BASE_URL=http://localhost:3001/api/v1
LOG_LEVEL=debug
SMS_PROVIDER=mock
PAYMENT_PROVIDER_KEY=

⚠️ Diqqat: Haqiqiy .env (parollar, token'lar, API kalitlar) hech qachon Git'ga commit qilinmaydi — u .gitignore'da bo'lishi kerak. Repo'da faqat bo'sh qiymatli .env.example turadi. PR'da .env yoki kalit ko'rinib qolsa — bu darhol xabar qilinadigan xavfsizlik muammosi.


9. Docker va Docker Compose: lokal muhit {#docker}

"Mening kompyuterimda ishlaydi" muammosining yechimi — Docker: ilova va uning bog'liqliklari (baza, kesh, navbat) bir xil "konteyner"larda ishlaydi.

TushunchaMa'nosi
ImageIlovaning tayyor "qolipi" (masalan, postgres:17)
ContainerImage'dan ishga tushirilgan nusxa
VolumeKonteyner o'chirilsa ham saqlanadigan ma'lumot (masalan, baza fayllari)
Docker ComposeBir nechta konteynerni bitta fayl bilan boshqarish

Docker'ni o'zingiz o'rnatasiz: macOS va Windows uchun Docker Desktop, Linux uchun Docker Engine (rasmiy hujjatga qarang). Compose faylining tavsiya etilgan nomi — compose.yaml (eski docker-compose.yml ham qo'llab-quvvatlanadi).

DemoBozor'ning lokal muhiti uchun o'quv misoli:

# compose.yaml — DemoBozor lokal muhiti (o'quv misoli)
services:
  db:
    image: postgres:17
    environment:
      POSTGRES_USER: demobozor
      POSTGRES_PASSWORD: local_only_password # faqat lokal uchun!
      POSTGRES_DB: demobozor
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data

  api:
    build: ./api # API'ning Dockerfile'i shu papkada
    environment:
      DATABASE_URL: postgres://demobozor:local_only_password@db:5432/demobozor
      SMS_PROVIDER: mock # haqiqiy SMS yubormaslik uchun
      LOG_LEVEL: debug
    ports:
      - "3001:3001"
    depends_on:
      - db

volumes:
  db-data:

QA'ning kundalik Compose buyruqlari

docker compose up -d                 # hamma servislarni fonda ishga tushirish
docker compose up -d --build         # kod o'zgargan bo'lsa — image'ni qayta yig'ib
docker compose ps                    # qaysi servis ishlayapti
docker compose logs -f api           # api loglarini real vaqtda kuzatish
docker compose logs --since 10m api  # oxirgi 10 daqiqa
docker compose logs -n 50 api        # oxirgi 50 qator
docker compose exec db psql -U demobozor -d demobozor -c "SELECT COUNT(*) FROM orders;"
docker compose restart api           # bitta servisni qayta ishga tushirish
docker compose down                  # konteynerlarni to'xtatib o'chirish (volume qoladi)

Test ma'lumotni noldan boshlash kerak bo'lsa:

docker compose down -v               # ⚠️ volume'lar ham o'chadi — bazadagi HAMMA ma'lumot ketadi
docker compose up -d

⚠️ Diqqat: down -v lokal test bazasi uchun qulay "reset" tugmasi, lekin u nomlangan volume'larni butunlay o'chiradi. Saqlab qolish kerak bo'lgan ma'lumot bo'lsa — avval eksport qiling. Umumiy serverlarda bu buyruqni hech qachon "sinab ko'rish" uchun ishlatmang.

Testcontainers — avtotestlar ichidan haqiqiy baza yoki brokerni konteynerda ko'tarib, test tugagach o'chiradigan kutubxonalar oilasi (Java, Go, .NET, Node.js, Python va boshqalar). Integratsiya testlarini "mock" o'rniga haqiqiy PostgreSQL bilan ishlatish uchun qulay — bunda Docker'ga tayanadi.


10. Loglar: darajalar, structured log, request ID {#loglar}

Log — tizim o'zi haqida yozib boradigan kundalik. QA uchun u eng kuchli dalil manbai: foydalanuvchi ko'rmagan narsani log ko'radi.

Log darajalari

DarajaQachon yoziladiDemoBozor misoli
TRACE / DEBUGBatafsil texnik tafsilotlar (odatda faqat dev/staging'da)"Promo KUZ2026 qoidasi tekshirilyapti"
INFOOddiy biznes hodisalari"Buyurtma 11 yaratildi"
WARNG'alati, lekin tizim ishlashda davom etyapti"To'lov provayderi javob bermadi, qayta urinish"
ERRORAmal bajarilmadi"Payment 502: provider timeout"
FATALServis ishlay olmaydi"Bazaga ulanib bo'lmadi, to'xtayapman"

QA uchun signal: foydalanuvchi "hech narsa bo'lmadi" desa, lekin logda WARN/ERROR bo'lsa — bu bug. Aksincha, oddiy holatda ERROR yozilsa — bu ham bug (shovqin haqiqiy xatolarni yashiradi).

Structured log (JSON) va jq

Zamonaviy servislar logni JSON qatorlar sifatida yozadi — mashina o'qishi oson:

cat > app.jsonl <<'EOF'
{"time":"2026-10-08T16:25:01.112Z","level":"info","requestId":"req-5a1c","method":"POST","path":"/api/v1/orders","status":201,"ms":184,"userId":9}
{"time":"2026-10-08T16:26:00.020Z","level":"warn","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","orderId":11,"msg":"retrying provider call"}
{"time":"2026-10-08T16:26:00.871Z","level":"error","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","status":502,"ms":850,"orderId":11,"msg":"provider timeout"}
{"time":"2026-10-08T16:28:30.004Z","level":"info","requestId":"req-7f3b","method":"POST","path":"/api/v1/payments","status":201,"ms":410,"orderId":11}
{"time":"2026-10-08T16:28:30.010Z","level":"error","requestId":"req-7f3b","orderId":11,"msg":"amount mismatch","expected":135000,"paid":130000}
{"time":"2026-10-08T16:31:40.101Z","level":"warn","requestId":"req-5a20","method":"POST","path":"/api/v1/auth/verify","status":429,"msg":"too many attempts"}
EOF
$ jq -c 'select(.level == "error")' app.jsonl
{"time":"2026-10-08T16:26:00.871Z","level":"error","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","status":502,"ms":850,"orderId":11,"msg":"provider timeout"}
{"time":"2026-10-08T16:28:30.010Z","level":"error","requestId":"req-7f3b","orderId":11,"msg":"amount mismatch","expected":135000,"paid":130000}

$ jq -r 'select(.requestId == "req-7f3a") | [.time, .level, .msg] | @tsv' app.jsonl
2026-10-08T16:26:00.020Z	warn	retrying provider call
2026-10-08T16:26:00.871Z	error	provider timeout

$ jq -s -c 'group_by(.level) | map({level: .[0].level, count: length})' app.jsonl
[{"level":"error","count":2},{"level":"info","count":2},{"level":"warn","count":2}]

$ jq -c 'select(.ms != null and .ms > 300) | {requestId, path, ms}' app.jsonl
{"requestId":"req-7f3a","path":"/api/v1/payments","ms":850}
{"requestId":"req-7f3b","path":"/api/v1/payments","ms":410}

Request ID — bitta so'rovning "pasporti"

Har bir kiruvchi so'rovga noyob ID beriladi va u shu so'rov o'tgan barcha servislar loglariga yoziladi. Ko'p loyihalarda u javob header'ida ham qaytadi (masalan, X-Request-ID — keng tarqalgan odat; taqsimlangan tizimlarda W3C standarti bo'lgan traceparent header'i ishlatiladi).

QA uchun oltin usul:

  1. DevTools Network yoki Proxyman'da muammoli so'rovni topasiz.
  2. Javob header'idan request ID'ni olasiz (masalan, req-7f3a).
  3. Shu ID bo'yicha loglardan butun "hikoya"ni chiqarasiz: retry, timeout, xato.
  4. Bug report'ga request ID, vaqt (UTC) va log parchasini qo'shasiz.

Dasturchi sizdan "qachon, qaysi foydalanuvchi, qaysi qurilma?" deb so'ramaydi — ID hammasini bog'laydi.

Markazlashgan log va xato tizimlari

Production'da loglar fayllarda emas, maxsus tizimlarda yig'iladi. QA odatda ularga brauzer orqali kiradi:

VositaNima uchunQA'ning odatiy so'rovi
Grafana LokiLoglarni yig'ish va LogQL bilan qidirish`{job="demobozor-api"} \= "req-7f3a"`
Kibana (Elastic)Loglar ustida qidiruv va dashboard'larrequestId : "req-7f3a" (KQL)
SentryXatolar: stack trace, breadcrumb'lar, qaysi relizda boshlanganiIssue havolasi va event ID'ni bug report'ga qo'shish
Firebase CrashlyticsMobil ilova crash'lariCrash-free foydalanuvchilar, crash stack trace

LogQL'da JSON loglarni maydon bo'yicha filtrlash: {job="demobozor-api"} | json | level="error". Monitoring va alerting chuqurroq — DevOps: observability.

⚠️ Diqqat: Logda parol, to'liq karta raqami, SMS kod yoki access token ko'rsangiz — bu xavfsizlik bug'i. Yuqoridagi logda telefon +99890***4567 ko'rinishida yashirilgan — to'g'ri amaliyot. Batafsil — QA 24.


11. Stack trace va mobil loglar {#stack-trace}

Stack trace — dastur yiqilgan paytdagi funksiyalar chaqiruvlari zanjiri. Qo'rqinchli ko'rinadi, lekin o'qish qoidasi oddiy.

Node.js'dagi haqiqiy misol — savatchasi hali yaratilmagan yangi foydalanuvchi checkout qilganda:

file:///app/src/cart.mjs:2
  return cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
              ^

TypeError: Cannot read properties of undefined (reading 'items')
    at cartTotal (file:///app/src/cart.mjs:2:15)
    at checkout (file:///app/src/checkout.mjs:4:17)
    at file:///app/server.mjs:5:1
    at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:661:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Node.js v24.14.1

Qanday o'qiladi:

  1. Xato turi va xabari — TypeError: Cannot read properties of undefined (reading 'items'): undefined qiymatdan .items o'qilmoqchi bo'lingan.
  2. Birinchi kadr (frame) — xato aynan qayerda: cart.mjs, 2-qator, 15-ustun, cartTotal funksiyasi.
  3. Kim chaqirgan — pastga qarab: checkout → server.mjs. node:internal/... kadrlari Node.js'ning ichki qismi, ularni odatda o'tkazib yuborasiz.
  4. Xulosa — user.cart undefined bo'lgan holat ko'zda tutilmagan. Test g'oyasi: "savatchasi bo'sh/yo'q foydalanuvchi checkout'ni bosadi".

Java'da (masalan, Spring backend) stack trace shunday ko'rinadi — bu namuna, tuzilishi muhim:

java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "uz.demobozor.order.OrderRequest.getPromoCode()" is null
	at uz.demobozor.promo.PromoService.apply(PromoService.java:42)
	at uz.demobozor.order.OrderService.create(OrderService.java:87)
	at uz.demobozor.order.OrderController.createOrder(OrderController.java:35)
	...

Bu yerda ham birinchi qator xato turi va sababini aytadi (promo-kod null, ya'ni promo-kodsiz buyurtma), keyingi qatorlar — loyiha paketidagi (uz.demobozor...) birinchi kadr. Java'da Caused by: bilan boshlangan qism ham bo'lishi mumkin — eng pastdagi Caused by odatda asl sababni ko'rsatadi.

💡 Maslahat: Bug report'ga stack trace'ni skrinshot emas, matn sifatida qo'shing (kod bloki ichida). Matnni qidirish, nusxalash va dublikatlarni topish mumkin; skrinshotni — yo'q.

Mobil loglar

PlatformaQayerdan olinadiBuyruq / yo'l
iOS SimulatormacOS log vositasi simulyator ichidaxcrun simctl spawn booted log stream --level debug --predicate 'process == "DemoBozor"'
iOS qurilmaXcode Console yoki macOS Console ilovasi (qurilma ulangan holda)Console.app → qurilmani tanlash → jarayon nomi bilan filtrlash
iOS crash'larXcode Organizer, TestFlight, CrashlyticsCrash log'ni bug report'ga ilova qilish
Androidadb logcat (emulator yoki USB orqali qurilma)adb logcat "*:E" — faqat xatolar; adb logcat -d > logcat.txt — joriy logni faylga

adb logcat filtri tag:daraja ko'rinishida: V (verbose), D (debug), I (info), W (warning), E (error), F (fatal), S (silent). zsh'da * belgisi maxsus ma'noga ega, shuning uchun filtrni qo'shtirnoqqa oling: adb logcat "DemoBozor:D *:S". Mobil testlash bo'yicha to'liq — QA 14.


12. Amaliy mashqlar {#mashqlar}

Mashqlar uchun 3- va 10-bo'limlardagi api.log va app.jsonl fayllarini yarating.

Mashq 1: Bitta to'lovning hikoyasi 🟢

api.log dan 11-buyurtma (order=11) bilan bog'liq barcha qatorlarni qator raqami bilan chiqaring. Nechta qator bor va ulardan nechtasi ERROR?

<details> <summary>💡 Javobni ko'rish</summary>

$ grep -n "order=11" api.log
3:2026-10-08T16:26:00.020Z WARN  [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
4:2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
6:2026-10-08T16:28:30.004Z INFO  [req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
7:2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000

$ grep "order=11" api.log | grep -c "ERROR"
2

4 ta qator, 2 tasi ERROR. E'tibor bering: order=11 qidiruvi GET /api/v1/orders/11 qatorini ushlamadi — u yerda format boshqa. Logda bir obyekt turli ko'rinishda yozilishi mumkin, shuning uchun bir nechta qidiruv bilan tekshiring.

</details>

Mashq 2: Eng sekin so'rovlar 🟡

api.log dagi ms= qiymatlari bo'yicha eng sekin 3 ta qatorni chiqaring.

<details> <summary>💡 Javobni ko'rish</summary>

$ grep -o "\[req-[a-z0-9]*\].*ms=[0-9]*" api.log | awk -F'ms=' '{print $2, $0}' | sort -rn | head -3 | cut -d' ' -f2-
[req-7f3a] POST /api/v1/payments order=11 status=502 ms=850
[req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
[req-5a1c] POST /api/v1/orders user=9 status=201 ms=184

awk har qatorning boshiga ms qiymatini qo'yadi, sort -rn shu son bo'yicha kamayish tartibida saralaydi, cut esa yordamchi sonni olib tashlaydi. Bu ishlaydi, lekin o'qish qiyin. Structured log bo'lsa, xuddi shu vazifa ancha sodda:

$ jq -s -c 'map(select(.ms != null)) | sort_by(-.ms) | .[:3] | map({requestId, path, ms})' app.jsonl
[{"requestId":"req-7f3a","path":"/api/v1/payments","ms":850},{"requestId":"req-7f3b","path":"/api/v1/payments","ms":410},{"requestId":"req-5a1c","path":"/api/v1/orders","ms":184}]

Saboq: matnli logni tahlil qilish mumkin, lekin JSON log va jq bilan ish ancha ishonchli. Loyihangiz hali matnli log yozsa — structured log'ga o'tishni taklif qilish ham QA'ning foydali hissasi.

</details>

Mashq 3: curl + jq 🟢

JSONPlaceholder'dan 1-foydalanuvchining postlari sonini va uning bajarilgan (completed: true) vazifalari sonini aniqlang.

<details> <summary>💡 Javobni ko'rish</summary>

$ curl -s "https://jsonplaceholder.typicode.com/posts?userId=1" | jq length
10
$ curl -s "https://jsonplaceholder.typicode.com/todos?userId=1&completed=true" | jq length
11

Query parametrlari bo'lgan URL'ni qo'shtirnoqqa oling: aks holda & belgisini shell "buyruqni fonda ishga tushir" deb tushunadi, ? esa zsh'da fayl nomi shabloni sifatida talqin qilinishi mumkin.

</details>

Mashq 4: Smoke skriptni kengaytirish 🟡

smoke.sh ga restful-booker'ning POST /auth endpoint'i to'g'ri login bilan token qaytarishini tekshiradigan qadam qo'shing.

<details> <summary>💡 Javobni ko'rish</summary>

token=$(curl -s -X POST "$BASE_URL/auth" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"password123"}' | jq -r '.token // empty')

if [ -n "$token" ]; then
  echo "✅ /auth → token olindi"
else
  echo "❌ /auth → token yo'q"
  failed=$((failed + 1))
fi

// empty — jq'da "maydon yo'q bo'lsa, bo'sh qaytar" degani; aks holda jq -r null so'zini chiqarib, tekshiruv aldanib qolardi. Bu qadamni if [ "$failed" -gt 0 ] dan oldin qo'ying.

</details>

Mashq 5: Reliz farqi va regression ko'lami 🟡

Dasturchi "v1.3 da faqat README va versiya o'zgardi, regression shart emas" demoqda. 7-bo'limdagi repo'da buni qanday tekshirasiz?

<details> <summary>💡 Javobni ko'rish</summary>

git log --oneline v1.2..v1.3      # qaysi commit'lar kirgan
git diff --stat v1.2 v1.3         # qaysi fayllar o'zgargan
git diff v1.2 v1.3 -- delivery.mjs

git diff --stat delivery.mjs faylida 9 qator qo'shilganini ko'rsatadi. Demak yetkazish narxi va muddati — regression ro'yxatida majburiy. Gap bilan emas, dalil bilan gaplashing: diff'ni ko'rsatib, aniq test ssenariylarini taklif qiling.

</details>

Mashq 6: Build bo'lmaydigan commit'lar 🔴

Katta loyihada bisect paytida ba'zi oraliq commit'lar umuman build bo'lmaydi. git bisect run uchun skriptni qanday yozasiz, toki bunday commit'lar "bad" deb belgilanmasin?

<details> <summary>💡 Javobni ko'rish</summary>

Build xatosida skript 125 bilan chiqishi kerak — git bu commit'ni o'tkazib yuboradi (git bisect skip kabi):

#!/usr/bin/env bash
# bisect-check.sh
npm ci --silent || exit 125          # bog'liqliklar o'rnatilmadi → test qilib bo'lmaydi
npm run build --silent || exit 125   # build bo'lmadi → o'tkazib yuboramiz
node ../qa-check.mjs                 # 0 = good, 1 = bad

Agar build xatosida exit 1 qilinsa, git bu commit'ni "bad" deb hisoblaydi va noto'g'ri commit'ni aybdor qilib ko'rsatishi mumkin.

</details>

Mashq 7: Lokal bazani noldan boshlash 🟡

Docker Compose'dagi DemoBozor muhitida test ma'lumotlar aralashib ketdi. Bazani butunlay tozalab, qayta ko'taring va API'ning oxirgi 50 qator logini ko'ring. Qaysi buyruq xavfli va nega?

<details> <summary>💡 Javobni ko'rish</summary>

docker compose down -v      # konteynerlar + nomlangan volume'lar (baza fayllari) o'chadi
docker compose up -d
docker compose logs -n 50 api

Xavfli qadam — down -v: u db-data volume'ini o'chiradi, bazadagi barcha ma'lumot qaytarib bo'lmas tarzda yo'qoladi. Lokal o'quv bazasi uchun bu aynan maqsad, lekin umumiy muhitlarda bunday buyruq faqat jamoa kelishuvi bilan ishlatiladi.

</details>

Mashq 8: Stack trace'dan test g'oyasigacha 🟡

11-bo'limdagi Java namunasini o'qing. Xato qaysi faylning qaysi qatorida, qaysi foydalanuvchi harakati uni keltirib chiqargan bo'lishi mumkin va qanday test case yozasiz?

<details> <summary>💡 Javobni ko'rish</summary>

  • Joy: PromoService.java, 42-qator, apply metodi (loyiha paketidagi birinchi kadr).
  • Sabab: getPromoCode() null qaytargan, kod esa unga toUpperCase() chaqirgan — promo-kodsiz buyurtma holati ko'zda tutilmagan.
  • Harakat: foydalanuvchi promo-kod maydonini bo'sh qoldirib buyurtma bergan (yoki mobil ilova maydonni umuman yubormagan).
  • Test case'lar: promo-kodsiz buyurtma (maydon yo'q), bo'sh satr "", faqat probellar " ", kichik harfli kuz2026 — hammasida buyurtma muvaffaqiyatli yaratilishi yoki tushunarli validatsiya xabari chiqishi kerak, 500 emas.

</details>


O'zingizni tekshiring {#checklist}

  • [ ] grep -n, -c, -i, -v, -E, -C flaglarini va pipe'ni ishlata olaman
  • [ ] > va >> farqini bilaman, dalilni faylga saqlay olaman
  • [ ] curl bilan status kod va JSON javob olaman, jq bilan filtrlayman
  • [ ] Exit code nima ekanini va CI uchun nega muhimligini tushuntira olaman
  • [ ] Feature branch'ga o'tib test qila olaman, git log v1..v2 bilan regression ko'lamini aniqlayman
  • [ ] git bisect (qo'lda va run bilan) yordamida aybdor commit'ni topa olaman
  • [ ] Docker Compose bilan muhitni ko'tarib, loglarini o'qiyman; down -v xavfini bilaman
  • [ ] Request ID bo'yicha logdan dalil yig'ib, stack trace'ni bug report'ga matn sifatida qo'shaman

Xulosa {#xulosa}

  • Terminal — QA'ning eng tez asbobi: grep, pipe, tail -f, curl va jq bilan log va API'ni sekundlarda tahlil qilasiz.
  • Exit code (0 = muvaffaqiyat) skriptlar, CI va git bisect run'ning umumiy tili.
  • Git QA uchun — vaqt mashinasi: branch'ni test qilish, reliz farqini ko'rish (git log v1.2..v1.3), blame va log -S bilan kontekst topish.
  • git bisect regressiyani keltirib chiqargan commit'ni binary search bilan topadi; tekshiruv skript bo'lsa — to'liq avtomatik.
  • Muhitlar, feature flag'lar va .env konfiguratsiyasini tushunish "nega staging'da ishlaydi-yu, prod'da yo'q?" savoliga javob beradi. Sirlar Git'ga tushmaydi.
  • Docker Compose lokal muhitni bir buyruq bilan ko'taradi; down -v — kuchli, lekin qaytarib bo'lmas "reset".
  • Loglar va request ID — bug report'ning eng kuchli dalili; stack trace'ni matn sifatida qo'shing, logda sirlar ko'rinsa — bu alohida bug.
  • Keyingi dars: QA 14: Mobil ilovalarni testlash — iOS va Android farqlari, Simulator, ADB, TestFlight va checklist

Manbalar {#manbalar}

  1. Apple — Use zsh as the default shell on your Mac
  2. Microsoft — Install WSL
  3. grep(1) — Linux manual page
  4. tail(1) — Linux manual page
  5. curl — man page
  6. jq — Manual va jq — Download
  7. Git — git-bisect documentation
  8. Git — git-switch, git-blame, git-stash
  9. GitHub CLI — gh pr checkout
  10. The Twelve-Factor App — Config
  11. Docker — Compose application model (compose.yaml)
  12. Docker — docker compose logs va docker compose down
  13. Docker Desktop
  14. Testcontainers
  15. W3C — Trace Context
  16. Grafana Loki — Log queries (LogQL)
  17. Elastic — KQL
  18. Sentry — Issues
  19. Firebase Crashlytics
  20. Android Developers — Logcat
  21. Apple — Console User Guide

Markdown manba

iOS Lessons