19-bo‘lim

Testlar va nosozliklarni topish

Nega test kerak, o'z sinov vositangizni yozish, Arrange-Act-Assert, chegaraviy holatlar, xUnit bilan tanishuv va nosozlikni qidirish usullari.

🕑 11 daqiqa o‘qish 📄 713 so‘z 👁 2 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Nega kerak
  2. Eng oddiy sinov vositasi
  3. Test yiqilganda
  4. Arrange - Act - Assert
  5. Nimani tekshirish kerak
  6. Chegaraviy holatlar ro'yxati
  7. Istisno tashlanishini tekshirish
  8. Haqiqiy loyihada - xUnit
  9. Nosozlikni qidirish
  10. Xulosa

Test - kodingiz kutilganidek ishlashini avtomatik tekshiradigan kod. U bir marta yoziladi va har o'zgarishdan keyin qayta ishlatiladi.

Nega kerak #

Qo'lda tekshirish ishlaydi, lekin faqat bir marta. Keyin kod o'zgaradi va siz hamma narsani qaytadan tekshirishga ulgurmaysiz.

Qo'ldaAvtomatik test
Har safar vaqt ketadiBir soniyada ishlaydi
Charchaganda o'tkazib yuboriladiHar doim bajariladi
Chegaraviy holatlar unutiladiYozib qo'yilgan
Nima tekshirilgani esda qolmaydiKod o'zi hujjat

Eng oddiy sinov vositasi #

Kutubxona o'rnatmasdan ham boshlash mumkin:

CSHARP
Tekshir.Teng(4, Kvadrat(2), "2 ning kvadrati");
Tekshir.Teng(0, Kvadrat(0), "0 ning kvadrati");
Tekshir.Teng(9, Kvadrat(-3), "manfiy sonning kvadrati");
Tekshir.Rost(Kvadrat(5) > 0, "kvadrat musbat");

Tekshir.Yakun();

int Kvadrat(int son) => son * son;

static class Tekshir
{
    private static int otdi;
    private static int yiqildi;

    public static void Teng<T>(T kutilgan, T haqiqiy, string nom)
    {
        if (Equals(kutilgan, haqiqiy))
        {
            otdi++;
            Console.WriteLine($"  OK    {nom}");
        }
        else
        {
            yiqildi++;
            Console.WriteLine(
                $"  XATO  {nom}: kutilgan {kutilgan}, haqiqiy {haqiqiy}");
        }
    }

    public static void Rost(bool shart, string nom) => Teng(true, shart, nom);

    public static void Yakun()
    {
        Console.WriteLine($"\nO'tdi: {otdi}, yiqildi: {yiqildi}");
    }
}
Natija
  OK    2 ning kvadrati
  OK    0 ning kvadrati
  OK    manfiy sonning kvadrati
  OK    kvadrat musbat

O'tdi: 4, yiqildi: 0

Test yiqilganda #

CSHARP
Tekshir.Teng(10, Qoshish(5, 5), "to'g'ri holat");
Tekshir.Teng(10, Qoshish(5, 4), "ataylab noto'g'ri");

Tekshir.Yakun();

int Qoshish(int a, int b) => a + b;

static class Tekshir
{
    private static int otdi;
    private static int yiqildi;

    public static void Teng<T>(T kutilgan, T haqiqiy, string nom)
    {
        if (Equals(kutilgan, haqiqiy))
        {
            otdi++;
            Console.WriteLine($"  OK    {nom}");
        }
        else
        {
            yiqildi++;
            Console.WriteLine(
                $"  XATO  {nom}: kutilgan {kutilgan}, haqiqiy {haqiqiy}");
        }
    }

    public static void Yakun() =>
        Console.WriteLine($"\nO'tdi: {otdi}, yiqildi: {yiqildi}");
}
Natija
  OK    to'g'ri holat
  XATO  ataylab noto'g'ri: kutilgan 10, haqiqiy 9

O'tdi: 1, yiqildi: 1

Yiqilgan test nima kutilgani va nima chiqqanini aytadi - shu tufayli muammoni topish oson.

Arrange - Act - Assert #

Har bir test uch qismdan iborat bo'lishi kerak:

CSHARP
// Arrange - shart-sharoit tayyorlanadi
var savat = new Savat();
savat.Qosh("Non", 4000);
savat.Qosh("Sut", 12000);

// Act - tekshiriladigan amal bajariladi
decimal jami = savat.Jami();

// Assert - natija tekshiriladi
Console.WriteLine(jami == 16000 ? "OK" : $"XATO: {jami}");

class Savat
{
    private readonly List<decimal> narxlar = [];

    public void Qosh(string nom, decimal narx) => narxlar.Add(narx);

    public decimal Jami() => narxlar.Sum();
}
Natija
OK

Bu tuzilma testni o'qishni osonlashtiradi va uni bo'lib yuborishdan saqlaydi.

Nimani tekshirish kerak #

Eng ko'p xato chegaralarda bo'ladi:

CSHARP
Tekshir.Teng("", Qisqartir("", 5), "bo'sh satr");
Tekshir.Teng("salom", Qisqartir("salom", 5), "aynan chegarada");
Tekshir.Teng("salo...", Qisqartir("salomlar", 5), "chegaradan uzun");
Tekshir.Teng("a", Qisqartir("a", 5), "bitta belgi");

Tekshir.Yakun();

string Qisqartir(string matn, int uzunlik) =>
    matn.Length <= uzunlik ? matn : matn[..uzunlik] + "...";

static class Tekshir
{
    private static int otdi, yiqildi;

    public static void Teng<T>(T kutilgan, T haqiqiy, string nom)
    {
        if (Equals(kutilgan, haqiqiy))
        {
            otdi++;
            Console.WriteLine($"  OK    {nom}");
        }
        else
        {
            yiqildi++;
            Console.WriteLine($"  XATO  {nom}: '{kutilgan}' != '{haqiqiy}'");
        }
    }

    public static void Yakun() =>
        Console.WriteLine($"\nO'tdi: {otdi}, yiqildi: {yiqildi}");
}
Natija
  OK    bo'sh satr
  OK    aynan chegarada
  XATO  chegaradan uzun: 'salo...' != 'salom...'
  OK    bitta belgi

O'tdi: 3, yiqildi: 1
Test o'zi ham xato bo'lishi mumkin

Uchinchi test yiqildi - lekin ayb kodda emas, testda.

Qisqartir("salomlar", 5) birinchi 5 ta belgini oladi - bu salom - va unga ... qo'shadi. Ya'ni to'g'ri natija salom..., men esa salo... deb kutgan edim. Sanashda bir belgi adashdim.

Bu juda ko'p uchraydi. Test yiqilganda avval kutilgan qiymatni qayta hisoblang: xato ko'pincha o'sha yerda bo'ladi.

Diqqat qiling: bitta test yiqilgani bilan qolganlari bajarilishda davom etdi va yakuniy hisob chiqdi. Yaxshi sinov vositasi birinchi xatoda to'xtamaydi - u hamma muammoni bir yo'la ko'rsatadi.

To'g'rilangan variant:

CSHARP
Tekshir.Teng("", Qisqartir("", 5), "bo'sh satr");
Tekshir.Teng("salom", Qisqartir("salom", 5), "aynan chegarada");
Tekshir.Teng("salom...", Qisqartir("salomlar", 5), "chegaradan uzun");
Tekshir.Teng("a", Qisqartir("a", 5), "bitta belgi");

Tekshir.Yakun();

string Qisqartir(string matn, int uzunlik) =>
    matn.Length <= uzunlik ? matn : matn[..uzunlik] + "...";

static class Tekshir
{
    private static int otdi, yiqildi;

    public static void Teng<T>(T kutilgan, T haqiqiy, string nom)
    {
        if (Equals(kutilgan, haqiqiy))
        {
            otdi++;
            Console.WriteLine($"  OK    {nom}");
        }
        else
        {
            yiqildi++;
            Console.WriteLine($"  XATO  {nom}: '{kutilgan}' != '{haqiqiy}'");
        }
    }

    public static void Yakun() =>
        Console.WriteLine($"\nO'tdi: {otdi}, yiqildi: {yiqildi}");
}
Natija
  OK    bo'sh satr
  OK    aynan chegarada
  OK    chegaradan uzun
  OK    bitta belgi

O'tdi: 4, yiqildi: 0

Chegaraviy holatlar ro'yxati #

TurTekshiriladigan holatlar
Sonlar0, manfiy, int.MaxValue, chegaradan bir kam va bir ko'p
SatrlarBo'sh, faqat bo'shliq, juda uzun, maxsus belgilar
To'plamlarBo'sh, bitta element, takrorlanuvchi elementlar
Havolalarnull
SanaKabisa yili, oy oxiri, yil chegarasi

Istisno tashlanishini tekshirish #

CSHARP
Tekshir.IstisnoTashlaydi<ArgumentException>(
    () => Bolish(10, 0), "nolga bo'lish");
Tekshir.IstisnoTashlaydi<ArgumentException>(
    () => Bolish(10, 2), "oddiy bo'lish");

Tekshir.Yakun();

int Bolish(int a, int b) =>
    b == 0 ? throw new ArgumentException("nolga bo'lib bo'lmaydi") : a / b;

static class Tekshir
{
    private static int otdi, yiqildi;

    public static void IstisnoTashlaydi<TIstisno>(Action amal, string nom)
        where TIstisno : Exception
    {
        try
        {
            amal();
            yiqildi++;
            Console.WriteLine(
                $"  XATO  {nom}: istisno kutilgan edi, tashlanmadi");
        }
        catch (TIstisno)
        {
            otdi++;
            Console.WriteLine($"  OK    {nom}");
        }
    }

    public static void Yakun() =>
        Console.WriteLine($"\nO'tdi: {otdi}, yiqildi: {yiqildi}");
}
Natija
  OK    nolga bo'lish
  XATO  oddiy bo'lish: istisno kutilgan edi, tashlanmadi

O'tdi: 1, yiqildi: 1

Haqiqiy loyihada - xUnit #

Amalda o'z vositangizni yozmaysiz - tayyor kutubxona ishlatiladi. Eng keng tarqalgani xUnit:

Terminal
dotnet new xunit -o MeningTestlarim
cd MeningTestlarim
dotnet add reference ../MeningLoyiham/MeningLoyiham.csproj
dotnet test

Test shunday ko'rinadi:

CSHARP
using Xunit;

public class KalkulyatorTestlari
{
    [Fact]
    public void Qoshish_IkkiMusbatSon_TogriNatija()
    {
        var k = new Kalkulyator();

        int natija = k.Qoshish(2, 3);

        Assert.Equal(5, natija);
    }

    [Theory]
    [InlineData(0, 0, 0)]
    [InlineData(1, 1, 2)]
    [InlineData(-5, 5, 0)]
    public void Qoshish_TurliQiymatlar(int a, int b, int kutilgan)
    {
        Assert.Equal(kutilgan, new Kalkulyator().Qoshish(a, b));
    }
}
AtributNima qiladi
[Fact]Oddiy test - bir marta ishlaydi
[Theory] + [InlineData]Bir xil test, turli ma'lumot bilan
Assert.EqualTenglikni tekshiradi
Assert.Throws<T>Istisno tashlanishini tekshiradi
Test nomini uch qismdan tuzing

Metod_Sharoit_KutilganNatija ko'rinishida:

  • Qoshish_IkkiMusbatSon_TogriNatija
  • Bolish_NolgaBolish_IstisnoTashlaydi
  • Qidir_RoyxatBosh_NullQaytaradi

Shunda test yiqilganda nomning o'zidan nima buzilganini tushunasiz - kodga qarash shart emas.

Nosozlikni qidirish #

Test yiqildi yoki dastur noto'g'ri ishlayapti. Endi nima qilish kerak?

UsulQachon
To'xtash nuqtasi (breakpoint)Eng kuchli usul - qiymatlarni ko'rish
Console.WriteLineTez, oddiy, har joyda ishlaydi
Debug.AssertShart buzilganda to'xtatadi
Stek izi (stack trace)Istisno qayerdan boshlangani
CSHARP
using System.Diagnostics;

int[] sonlar = [5, 3, 8];
int jami = 0;

foreach (int son in sonlar)
{
    jami += son;
    Debug.WriteLine($"[debug] son={son}, jami={jami}");
}

Debug.Assert(jami > 0, "yig'indi musbat bo'lishi kerak");

Console.WriteLine($"Yig'indi: {jami}");
Natija
Yig'indi: 16

Debug.WriteLine va Debug.Assert faqat Debug rejimida ishlaydi. Release da ular kompilyatsiyadan butunlay chiqarib tashlanadi - shuning uchun tayyor dasturni sekinlashtirmaydi.

Nosozlikni topishning izchil usuli

19-bo'limdagi kompyuter savodxonligi qoidasi bu yerda ham ishlaydi:

  1. Xato xabarini to'liq o'qing - unda ko'pincha javob bor;
  2. Stek izining birinchi qatoriga qarang - u sizning kodingiz;
  3. Nima o'zgarganini eslang - oxirgi ishlagan holatdan beri;
  4. Muammoni kichraytiring - eng kichik takrorlanadigan misol yarating;
  5. Bir vaqtda bitta narsani o'zgartiring.

To'rtinchi qadam eng kuchlisi: muammoni o'n qatorgacha qisqartirsangiz, sabab odatda o'z-o'zidan ko'rinadi.

Amaliy topshiriq
  1. Tekshir sinfini yozing va uchta testdan o'tkazing.
  2. Ataylab noto'g'ri test yozib, xabarni ko'ring.
  3. Arrange-Act-Assert tuzilmasida test yozing.
  4. Qisqartir metodi uchun chegaraviy holatlarni tekshiring.
  5. Bo'sh to'plam va null uchun testlar qo'shing.
  6. IstisnoTashlaydi bilan istisno tashlanishini tekshiring.
  7. dotnet new xunit bilan test loyihasini yarating.
  8. [Theory] va [InlineData] bilan bir nechta holatni sinang.
  9. Debug.WriteLine bilan sikl ichidagi qiymatlarni kuzating.
  10. Bir muammoni eng kichik takrorlanadigan misolgacha qisqartiring.

Xulosa #

  • Test bir marta yoziladi, har o'zgarishdan keyin ishlaydi.
  • Har bir test Arrange - Act - Assert tuzilmasida bo'lsin.
  • Eng ko'p xato chegaralarda: bo'sh, nol, bitta element, null, eng katta qiymat.
  • Test yiqilsa, avval kutilgan qiymatni qayta tekshiring - xato testda bo'lishi mumkin.
  • Haqiqiy loyihada xUnit: [Fact], [Theory], Assert.Equal.
  • Test nomi Metod_Sharoit_KutilganNatija ko'rinishida bo'lsin.
  • Debug.WriteLine va Debug.Assert faqat Debug rejimida ishlaydi.
  • Nosozlikni topishda muammoni kichraytirish eng samarali usul.

Keyingi va oxirgi bo'limda hamma o'rganganimizni bitta loyihada birlashtiramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.