Asosiy kontentga o‘tish
Innovialabs

Property-based testlash: Hypothesis va fast-check amalda

Chuqur3 daq

Qisqacha

Bir nechta misol o‘rniga istalgan kirish uchun to‘g‘ri bo‘lgan xossani tasvirlaysiz, Hypothesis yoki fast-check esa yuzlab holatlar yaratib, topilgan xatoni minimal misolgacha qisqartiradi.

Misollar o‘rniga xossalar

Oddiy test misolni tekshiradi: «2 va 3 uchun yig‘indi 5 ga teng». Property-based test istalgan kirish ma’lumoti uchun bajarilishi kerak bo‘lgan tasdiqni tekshiradi: «saralash natijasi tartiblangan va o‘sha elementlarni o‘z ichiga oladi».

Kutubxona o‘zi ko‘plab kirishlar yaratadi — bo‘sh ro‘yxatlar, manfiy sonlar, Unicode, juda uzun satrlar — va xossa buziladigan holatni qidiradi. Bu oddiy testlarni yaxshi to‘ldiradi: misollar ma’lum xatti-harakatni qayd etadi, xossalar esa siz o‘ylamagan narsani qidiradi.

  • Python — Hypothesis.
  • JavaScript va TypeScript — fast-check.

Generatorlar va shrinking

Generator (Hypothesis’da — strategy, fast-check’da — arbitrary) qanday ma’lumot yaratishni tasvirlaydi: st.integers(), st.lists(st.text()), fc.array(fc.integer()), fc.record({...}). Generatorlar birlashtiriladi, shuning uchun buyurtma yoki foydalanuvchi obyektini yig‘ish mumkin.

Shrinking — asosiy qulaylik. Ulkan tasodifiy kirishda xato topilganda kutubxona uni qadamma-qadam soddalashtiradi, toki xato hamon takrorlanadigan minimal misolga yetguncha. 80 ta tasodifiy sonli ro‘yxat o‘rniga siz [0, -1] ni ko‘rasiz.

Qaysi xossalarni tekshirish kerak

XossaMisol
Round-tripdecode(encode(x)) == x, parse(format(x)) == x
Invariantsaralashdan keyin uzunlik o‘zgarmaydi, elementlar tartiblangan
Idempotentliknormalize(normalize(x)) == normalize(x)
Orakultez funksiya oddiy sekin versiya bilan mos keladi
Yiqilmaydifunksiya har qanday to‘g‘ri kirishda istisno tashlamaydi

Round-trip va «yiqilmaydi» xossalaridan boshlang — ularni ifodalash eng oson.

Hypothesis: teng bo‘linmaydigan pul

Funksiya tiyindagi summani n qismga bo‘ladi:

from hypothesis import given, strategies as st

def split_amount(total, n):
    part = round(total / n)
    return [part] * n

@given(st.integers(min_value=0, max_value=10**9),
       st.integers(min_value=1, max_value=100))
def test_parts_sum_to_total(total, n):
    assert sum(split_amount(total, n)) == total

(100, 4) kabi misollar o‘tadi, lekin Hypothesis tezda buzilishni topadi va uni total=1, n=2 ga o‘xshash holatgacha qisqartiradi: qismlar yig‘indisi dastlabki summaga teng emas. Tuzatish — qoldiqni taqsimlash:

def split_amount(total, n):
    q, r = divmod(total, n)
    return [q + 1] * r + [q] * (n - r)

fast-check: o‘zimiz yozgan serializatsiya

Oddiy funksiya obyektni key=value&... satriga aylantiradi:

import fc from "fast-check";

const stringify = (o: Record<string, string>) =>
  Object.entries(o).map(([k, v]) => `${k}=${v}`).join("&");

fc.assert(
  fc.property(fc.dictionary(fc.string(), fc.string()), (obj) => {
    expect(parse(stringify(obj))).toEqual(obj);
  })
);

fast-check & yoki = belgisi bor kalit yoki qiymatni topadi va round-trip buziladi. { name: "Ali" } bilan qo‘lda yozilgan test bu xatoni hech qachon ko‘rsatmasdi. Tuzatish — qiymatlarni ekranlash, masalan encodeURIComponent orqali.

Qanday og‘riqsiz joriy qilish mumkin

  1. Sof funksiyalarni tanlang: parserlar, formatterlar, hisob-kitoblar, ma’lumotlarni o‘zgartirish.
  2. Bitta xossani yozing va generatorni real domen bilan cheklang (diapazonlar, uzunliklar).
  3. Topilgan har bir kontrmisolni oddiy misol-test sifatida saqlang — bu regressiya testi.
  4. CI’da yiqilganda seed’ni qayd eting: ikkala kutubxona ham ishga tushirishni qanday takrorlashni aytadi.
  5. Xossa ichida implementatsiyani takrorlamang, aks holda test o‘sha xatoni qaytaradi.

Keng tarqalgan xatolar

  • Juda keng generatorlar, natijada holatlarning ko‘pchiligi filtrlar tomonidan tashlab yuboriladi.
  • Hech narsani tekshirmaydigan, oddiygina har doim to‘g‘ri xossa.
  • Sekin testlar: har bir iteratsiya ichida ma’lumotlar bazasi bilan og‘ir ishlar.

Ko‘p beriladigan savollar

Yo‘q, ular to‘ldiradi. Misollar aniq xatti-harakat va biznes qoidalarini hujjatlashtiradi, xossalar esa qo‘lda o‘ylab topish qiyin bo‘lgan chekka holatlarni qidiradi.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.