Test best practices — AAA pattern, naming, coverage, TDD kirish
Muammodan boshlaylik
Loyihada 800 ta test bor. Lekin:
Test1,Test2,BuyurtmaTest— yiqilganda nima buzilganini bilish uchun kodni o'qish kerak- 30 ta test har safar emas, ba'zan yiqiladi — jamoa ularni e'tiborsiz qoldira boshladi
- Har bir refactoring da 50 ta test sinadi, garchi xulq o'zgarmagan bo'lsa ham
- Coverage 90%, lekin haqiqiy xatolar baribir production ga yetib boryapti
Testlar bor — ishonch yo'q.
Hayotiy o'xshatma
Tutun detektori. Yaxshi detektor haqiqiy yong'inda albatta chalinadi va tuxum qovurganingizda chalinmaydi. Har kuni behuda chalinadigan detektorni odamlar o'chirib qo'yadi — va haqiqiy yong'in kuni u jim turadi. Ishonchsiz test — o'chirib qo'yilgan detektordan ham yomon: u xavfsizlik hissini beradi.
1. AAA — aniq tuzilma
[Fact]
public void Savat_mahsulot_qoshilsa_jami_oshadi()
{
// Arrange
var savat = new Savat();
var telefon = new Mahsulot { Narx = 1_000_000 };
// Act
savat.Qosh(telefon, soni: 2);
// Assert
Assert.Equal(2_000_000, savat.Jami);
}
- Bitta Act — test bitta xulqni tekshiradi
- Arrange katta bo'lsa — yordamchi metod yoki builder
2. Nomlash — test hujjat bo'lsin
Shablon: Metod_Sharoit_KutilganNatija
| ❌ | ✅ |
|---|---|
Test1 |
Hisobla_vip_mijoz_5_foiz_qoshimcha_chegirma |
BuyurtmaTest |
Rasmiylash_omborda_yetarli_emas_xato_tashlaydi |
TestLogin |
Login_notogri_parol_401_qaytaradi |
Yiqilgan test nomini o'qib, kodga qaramasdan nima buzilganini tushunish kerak:
Failed: Rasmiylash_omborda_yetarli_emas_xato_tashlaydi
3. Xulqni tekshiring, amalga oshirishni emas
// ❌ ichki tafsilotga bog'langan
_repo.Verify(r => r.OlAsync(5, It.IsAny<CancellationToken>()), Times.Once);
_repo.Verify(r => r.Qosh(It.IsAny<Buyurtma>()), Times.Once);
_repo.Verify(r => r.SaqlaAsync(It.IsAny<CancellationToken>()), Times.Once);
// ✅ kuzatiladigan natija
var buyurtma = await service.RasmiylashAsync(dto, ct);
Assert.Equal(BuyurtmaHolati.Tolangan, buyurtma.Holat);
Assert.Equal(250_000, buyurtma.Summa);
Kod ichki tuzilishi o'zgarsa (refactoring), lekin xulqi bir xil qolsa — test sinmasligi kerak.
4. Testlar mustaqil va deterministik
// ❌ vaqtga bog'liq — ba'zan yiqiladi
Assert.True(token.Tugaydi > DateTime.UtcNow);
// ✅ vaqtni boshqarish
var vaqt = new FakeTimeProvider(new DateTimeOffset(2026, 11, 8, 12, 0, 0, TimeSpan.Zero));
var service = new TokenService(vaqt);
var token = service.Yarat();
vaqt.Advance(TimeSpan.FromMinutes(16));
Assert.True(service.Eskirganmi(token));
"Ba'zan" yiqiladigan (flaky) testlar sabablari:
- Joriy vaqt va sana
- Tasodifiy sonlar (seed siz)
- Testlar o'rtasidagi umumiy holat (statik o'zgaruvchilar, bitta baza yozuvlari)
Task.Delaybilan "kutib turish"- Tashqi servislar va tarmoq
[!WARNING] Flaky testni "qayta ishga tushirsa o'tadi" deb qoldirmang — darhol tuzating yoki vaqtincha
Skipbilan o'chirib, vazifa oching. Bitta flaky test butun test to'plamiga ishonchni yo'qotadi.
5. Test ma'lumotlari — builder
public class BuyurtmaBuilder
{
private int _mijozId = 1;
private decimal _summa = 100_000;
private BuyurtmaHolati _holat = BuyurtmaHolati.Yangi;
public BuyurtmaBuilder Mijoz(int id) { _mijozId = id; return this; }
public BuyurtmaBuilder Summa(decimal s) { _summa = s; return this; }
public BuyurtmaBuilder Bekor() { _holat = BuyurtmaHolati.Bekor; return this; }
public Buyurtma Yarat() => new() { MijozId = _mijozId, Summa = _summa, Holat = _holat };
}
var b = new BuyurtmaBuilder().Summa(2_000_000).Bekor().Yarat();
Test faqat muhim qiymatlarni ko'rsatadi; qolganlari — mantiqli sukut qiymatlari.
6. Coverage — vosita, maqsad emas
dotnet test --collect:"XPlat Code Coverage"
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"**/coverage.cobertura.xml" -targetdir:"coverage" -reporttypes:Html
| Coverage nima beradi | Nima bermaydi |
|---|---|
| Qaysi kod umuman ishlamaganini ko'rsatadi | Testlar to'g'ri narsani tekshirishini kafolatlamaydi |
| Test qilinmagan muhim tarmoqlarni topish | Assert siz test ham coverage ni oshiradi |
[!TIP] Coverage ni qat'iy maqsad (masalan, "100%") qilmang — jamoa ma'nosiz testlar yozib raqamni ko'taradi. Muhim biznes mantiq (to'lov, chegirma, ruxsatlar) yaxshi qoplanganiga e'tibor bering; oddiy DTO va konfiguratsiyaga vaqt sarflamang. Testlar sifatini tekshirish uchun — mutation testing (Stryker.NET): kodni ataylab buzib, testlar buni ushlashini tekshiradi.
7. Tezlik va tuzilma
- Unit testlar — butun to'plam soniyalarda; sekin bo'lsa, dasturchilar ishga tushirmay qo'yadi
- Integration testlar — alohida loyiha yoki kategoriya (
[Trait("Kategoriya", "Integration")]) - Test loyihasi tuzilmasi asosiy loyihani takrorlaydi:
Services/ChegirmaHisoblagichTests.cs - CI da har bir PR da barcha testlar
dotnet test --filter "Kategoriya!=Integration" # tez lokal ishga tushirish
8. Xato topilsa — avval test
Production da xato topildi:
- Xatoni takrorlaydigan yiqiladigan test yozing
- Kodni tuzating — test yashil
- Bu xato endi hech qachon jimgina qaytmaydi
Tez-tez uchraydigan xatolar
Testda mantiq (if, sikllar, hisoblash) — testning o'zida xato bo'lishi mumkin; kutilgan qiymatni to'g'ridan-to'g'ri yozing.
Private metodlarni test qilish — public xulq orqali tekshiring.
Assert siz test — hech narsani tekshirmaydi, faqat exception yo'qligini.
Xulosa
Yaxshi test — ishonchli detektor: xato bo'lsa yiqiladi, bo'lmasa — yo'q. AAA tuzilmasi, bitta Act; nom — Metod_Sharoit_Natija, hujjat vazifasini bajaradi. Xulqni tekshiring, ichki amalga oshirishni emas — refactoring testlarni sindirmasin.
Mustaqil va deterministik: vaqt (FakeTimeProvider), tasodif, umumiy holatni boshqaring; flaky testni darhol tuzating. Builder lar — o'qiladigan test ma'lumotlari. Coverage — vosita, maqsad emas; muhim mantiqqa e'tibor, mutation testing. Xato topilsa — avval yiqiladigan test.
Keyingi bo'lim
80-dars: Docker — .NET ilovani konteynerga solish, Dockerfile