إيه هو الUnit testing

إيه هو ال Unit testing

هنتكلم هنا عن إيه هو ال Unit testing كفكرة عامة، مع اجزاء من الكود اللازم بشكل مبسط

لو هنعرف الunit testing كود في سطر واحد، نقدر نقول انه هو عبارة عن كتابة كود يتأكد من انه الفانكشنز اللي انت كتبتها، بتشتغل زي ما احنا عاوزين، ديمًا، و بتؤدي الهدف المطلوب منها ديمًا

ليه ؟ فيه اسباب كتيرة، ممكن نقول منها

علشان احيانًا بنكتب كود، و نيجي بعد فترة كبيرة، مش فاكرين هو كان بيعمل، و نعدل عليه، و الابلكييشن يشتغل عادي،

  1. احيانا بيكون عندنا bug، نيجي نحلها عن طريق انه نغير في كود مكتوب من زمان، و شغال، و نلاقي الbug اتحلت، بس مناخدش بالنا انه و احنا بنحلها بوظنا حاجة تانية مثلا
  2. احيانًا لو تيم بيشتغل مع بعضه، ممكن واحد يكتب كود شغال، يصحى صاحبه يعدل على الكود دا وسط شغله، و مياخدش باله انه بوظ حاجة او غير حاجة اساسية المفروض الفانكشن تعملها
  3. تقدر تكتشف الbugs قبل ما التيستر، او الكلاينت، يكتشفها
  4. بتقلل الكود اللي ممكن يبقى ملوش لازمة في الفانكشن بتاعتك و بتساعد على كتابة كود افضل و انضف - بيساعد على دا حاجات زي TDD

دلوقتي قولنا تعريف بسيط، و قولنا بعض الاسباب اللي المفروض تخليك تكتب unit testing، نشوف مثال، و مننساش ديمًا الهدف بتاعنا

الهدف : اي فانكشن بنكتبها في الكود العادي بتاعنا، تشتغل ديمًا زي ما احنا عاوزين، و تحقق المطلوب منها

بمعنى إيه ؟ تخيل لو عندنا الفانكشن دي

func insertDot(to sentance: String) -> String {
    //if the last character in sentance is "." will return the sentance without any modification
    guard sentance.last != "." else { return sentance }

    //return the senance with a dot added at the end
    return sentance + "."

}

الهدف في الفانكشن دي هدفها انها تضيف نقطة في اخر الجملة اللي هتجيلها

الفانكشن دي بتحقق الهدف ازاي ؟ عن طريق حاجتين

  1. لو الجملة اللي اللي عاوزين نضيفلها نقطة، اصلا اخرها نقطة، في الحالة دي احنا مش عاوزين يتضافلها نقطة كمان
  2. لو الجملة مفيهاش نقطة في آخر الجملة، نضيف لها نقطة

اللي احنا عاوزين نعمله، اننا نحافظ على الأهداف دي، بمعنى آخر، عايزين نكتب كود، يتأكد، انه ديما، الفانكشن دي بتحقق الهدفين دول.، الكود اللي احنا هنكتبه بيسمى“ test“ او بشكل ادق بيسمى unit test, هنحتاج نكتب ٢ unit tests، كل test بيتأكد من هدف واحد من الاهداف بتاعتنا

هنا هنكتب الكود اللي محتاجينه علشان نحقق الهدفين دول - من غير توضيح تفاصيل الكود دا هيكون مكتوب فين - علشان نركز على الفكرة بس


الكود اللازم لعمل test unit للهدف الاول في الفانكشن دي:

و الهدف من التيست دا: انه لما لما الفانكشن اللي بنعملها تيست، يجيلها Mostfa. النتيجة تكون Mostfa.

func test_NoDublicate_dots() { //1

        let output = insertDot(to: "Mostfa.") //2


           XCTAssertEqual(output, "Mostfa.", "No dot's should be added") //3

    }

في ١:

بنكتب اسم الفانكشن ، وبنقول هي هتعمل إيه test لإيه في الأسم، هنا الأسم بيقول انه مش عاوزين اكتر من نقطة في الجملة اللي هتطلع لنا

في ٢:

بنعمل كول للفانكشن اللي احنا بنجربها و هنحفظ النتيجة في output

لاحظ انه الجملة اللي بنضيفلها نقطة في آخرها هنا اصلا، فيها نقطة، و من المفترض انه الجملة ترجع زي ماهي، من غير نقطتين في الآخر

في ٣: بنستخدم فانكشن موجودة في الفريم ورك اللي بنستخدمها للتيست نعمل تيست، اسمها XCTAssertEqual ببساطة احنا بنقول إيه الهدف بتاعنا، او ايه الشيئ اللي عاوزينه يحصل، احنا عاوزن ، output يساوي. .Mostfa ، لأنه دا الهدف بتاعنا،

الفانكشن دي ممكن نقول انها بتعمل كدا

func test_NoDublicate_dots() {

        let output = insertDot(to: "Mostfa.")
        XCTAssertEqual(output, "Mostfa.", "No dots should be added")

        if output == "Mostfa." {
            //we are happy, no errors!
        } else {
            assertionFailure("stop here!, we are not happy, that's not supposed to happen")
        }
    }

لما تشغل التيست دا، النتيجة هتكون علامة صح ✅ علشان فعلا الفانكشن اللي بنعملها تيست insertDot، فعلا مش بتضيف نقطة للجملة لو في اخرها نقطة

كدا مبروك اول تيست عملناه،

لو واحد مجنون راح لعب في الفانكشن الاساسية وخلاها كدا

func insertDot(to sentance: String) -> String {
    //if the last character in sentance is "." will return it with any modification
    guard sentance.last != " " else { return sentance }

    //return the senance with a dot added at the end
    return sentance + "."

}

و جينا نشغل التيست اللي كتبناه هنلاقي النتيجة كدا

وجنبها اكس ❌

ليه ؟ لأنه الtest لما اشتغل لقى انه النتيجة ..Mostfa و دا مش اللي احنا متوقعينه، و اللي مش المفروض الفانكشن دي تعمله

في الوضع الحالي، بعد اي شغل نعمله في البروجكت، هنعمل run للtest فانكشنز اللي موجودة، المفروض لو شغلنا سليم، كله يبقى اخضر، لكن لو فيه حاجة لونها احمر، هنعرف انه احنا بوظنا حاجة، نروح نشوف بوظنا إيه

نيجي للهدف التاني بتاعنا اللي بنعمله test وهو منطقي اكتر،

في التيست دا، بنتأكد انه لو كان الجملة بتاعتنا مفيش نقطة في آخرها،

func test_dot_isAdded() {
        let output = insertDot(to: "Essam")
        XCTAssertEqual(output, "Essam.")
    }

بكل بساطة بنعمل فاريبل output و بقول للفانكشن بتاعتنا تضيف نقطة في آخر الجملة Essam

و بستخدم نفس الفانكشن اللي استخدمناها فوق، بنقول، انه احنا بنتوقع، انه ديمًا، الأوت بوت يكون .Essam

ولو كل حاجة ماشية زي ما توقعنا

ولو فيه واحد مجنون كان بيشتغل على الكود، و عمل تغير على الفانكشن الاصلية بتاعنا و خلاها كدا مثلا

func insertDot(to sentance: String) -> String {
    //if the last character in sentance is "." will return it with any modification
    guard sentance.last != "." else { return sentance }

    //return the senance with a dot added at the end
    return sentance + "💕"

}

لما نيجي نشغل التيست، هنلاقي النتيجة كدا

ودا متوقع، بيقولنا انه المفروض لما الجملة تكون Essam الناتج يكون .Essam مش يكون 💕Essam، فأحنا نروح نبص على الفانكشن و نشوف غيرنا فيها إيه علشان الtest ينجح تاني

ولو كل حاجة مظبوطة، دي الصورة النهائية اللي المفروض نحصل عليها

و بكدا نكون وصلنا نهاية المقالة النهاردة، احنا هنا اتكلمنا عن مقدمة عن الtesting، مع مثال بسيط جدا جدا جدا، بيوضح ازاي بنفكر في التيستنج، و المفروض نعمل إيه علشان نعمل تيست

فيه حاجات ناقصة، زي مثلا الكود بتاعت التيست بيتكتب فين بالظبط في البروجكت، و ازاي نعمل تيست لحاجة معقدة اكتر من كدا، كل النقاط دي ممكن نتكلم عنها في جزء تاني بيشرح الموضوع تفصيلا،

و نعمل tests لل API layer بتاعنا، بشكل متقدم اكتر.