طريقة كتابة اختبارات الـ JUnit في لغة الجافا

Mohammad Laifمنذ 11 شهر

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

هذه المقالة تمهيديه في شرح و كتابة اختبارات الـ Junit للغة الـ Java. والتي من خلالها اصبو الى كتابة المزيد من المقالات في مجال الاختبارات للجافا و للإندرويد في المستقبل ان شاء الله. لإني ارى ان هناك شح كبير جداً في هذا المجال و ان شاء الله اوفق ولو بسد جزء بسيط به, ولا ارى ضرر في كتابة الاخوان في هذا المجال لمن يريد, فالقارئ ربما يفهم من هذا المقال او من ذلك المقال.

 

ماذا سوف تقرئ في هذه المقالة

ماهي مكتبة الـ Junit وماهي متطلباتها؟ ماهي الطريقة التي تتم بها كتابة هذا النوع من الاختبارات؟ ماهي اهم الـ Annotations, و الـ Assertions المستخدمة في هذه المكتبة. مع امثلة برمجية وبعض الملاحظات لتقريب المفهوم. وسوف نرى كيفية انشاء مجلد خاص بهذه الاختبارات, وانشاء اول كلاس لكتابة الاختبارات به, ثم كيفية تشغيلها.

 

ماهو الـ JUnit

عبارة عن مكتبة لكتابة وتشغيل الاختبارات المتكرره بشكل سهل وسلس.

 

الموقع الرسمي

JUnit

 

المتطلبات

  • مكتبة الـ JUnit للإختبارات, الاصدار الرابع (مميزة هذا الاصدار انه مدعوم في الاندرويد كذلك, فجميع هذه الاكواد تعمل في الـ Android Studio بطلاقه).
  • معرفة كيفية استخدام الـ Annotations الخاص بالـ JUnit.

 

طريقة كتابة هذ النوع من الاختبارات
يقوم على كتابة دالات اختبار Unit Test في كلاس خاصة بها, ومن خلالهم تقوم باختبار دالاتك الحقيقه في مشروعك. وكل من هذه الدالات الاختبارية يأتي فوقها Annotation خاص بالـ JUnit تحدده انت حسب الغرض.

 

اهم الـ Annotations المستخدمة في اجراء اختبارات الـ JUnit
هذا جدول يوضح اهم الـ Annotations التي سوف تحتاجها في كتابة دالات اختباراتك. من الافضل حفظهم عن ظهر قلب.

testannotation.thumb.png.8876cfb6226400fc88d6bab135d54b87.png

 

مثال برمجي لتوضيح تسلسل عمل هذه الـ Annotations على دوال الاختبارات


package com.company;
import org.junit.*;

public class MainTest {

    @BeforeClass
    public static void preSetup(){
        System.out.println("preSetup() Runs!");
        System.out.println("-----------------");
    }

    @Before
    public void setup(){
        System.out.println("setup() Runs - Preparing Object");
    }

    @Test
    public void sum1_test(){
        System.out.println("sum1_test() Runs");
    }

    @Test
    public void sum2_test(){
        System.out.println("sum2_test() Runs");
    }

    @Ignore
    @Test
    public void sum3_test(){
        System.out.println("sum3_test() Runs");
    }

    @After
    public void clean(){
        System.out.println("clean() Runs = Cleaning test environment");
    }

    @AfterClass
    public static void postClean(){
        System.out.println("-----------------");
        System.out.println("postClean() Runs!");
    }
}

 

الناتج

preSetup() Runs!
-----------------
setup() Runs - Preparing Object
sum1_test() Runs
clean() Runs = Cleaning test environment

setup() Runs - Preparing Object
sum2_test() Runs
clean() Runs = Cleaning test environment

Test ignored.
-----------------
postClean() Runs!

 

ملاحظات

  • الدالتين setup و clean تم تشغيلهم اكثر من مره, لكل دالة اختبار, وهذا يعود لتطبيق النوتيشن After و Before اعلاهم.
  • الدالتين preSetup و postClean تم تشغيلهم فقط مره واحده, لهذه الكلاس, وهذا يعود لتطبيق النوتيشن BeforeClass و AfterClass اعلاهم ويجب عندها ان يكونان static.
  • دالة الاختبار المسمية بالـ sum3_test قد تم تجاهلها, وهذا يعود الى استخدام النوتيشن Ignore اعلاها.
  • اما دوال الاختبار لدينا المسماه sum1_test و sum2_test فقد تم تشغيلهم بسلاسة ونجاح.

 

انشاء بيئة الاختبارات الخاصة بالـ JUnit على مشروع جافا

الان لنقم بإنشاء بيئة الاختبارات الخاصة بنا, والتي من خلالها سوف نقوم باختبار مشروعنا التجريبي (عباره عن حاسبة اطفال بلغة الجافا). هذه الطريقة تمكنك من انشاء بيئة الاختبار يدوياً Best Practice.

  1. قم بتشغيل برنامجك المفضل للجافا (في هذا الشرح IntelliJ IDEA).
  2. انشئ مشروع جافا جديد 1.8 ولاتنسى اختيار الـ Command Line App او اختر مشروع سابق.
  3. انشئ مجلد جديد في مسار مشروعك وسمه مثلاً test.
  4. علم هذا المجلد بانه خاص للإختبارات, حتى يفهم الـ IntelliJ IDEA.
  5. اذهب الى اسم كلاسك الرئيسية واضغظ عليها بالزر الايمن للماوس ومن القائمة اختر Go To ثم Test.
  6. اضغظ على Create New Test... في النافذة المنبثقة.
  7. ستظهر لك نافذة جديده للإختبارات, اختر مكتبة الـ JUnit 4 المتطابقة مع هذا الشرح.
  8. انتباه: اذا رأيت الرسالة JUnit4 library not found in the module اضغظ على Fix.
  9. ثم استخدم المكتبة الموجودة بمسار الـ IntelliJ او قم بتحميلها وتحديد مسار اخر لها.

 

الخطوات بالصور حتى يسهل الأمر

  • انشاء مجلد الاختبارات

create-test-folder.png.33464bd6da5de1515debe48029ef52ab.png

 

  • تعليم هذا المجلد وجعله خاص للإختبارات

make-folder-testable.thumb.png.cadc233cd78b716a8f0d3b42d2001152.png

 

  • انشاء اول اختبار للكلاس الرئيسية

create-test-for-class.png.94d213b2fd8f3563a2834567a961553e.png

 

  • ثم انشاء اختبار جديد

create-test.png.6fb56d8250bc83d66d68332cad907944.png

 

  • تعديل الاعدادات واختيار مكتبة الاختبارات كأول مره فقط (لاتنسى اصلاح خلل ايجاد مسار المكتبة)

create-junit-test.png.6629ffbdaca402e7ba7e861141f04263.png

 

  • اصلاح Fix خلل ايجاد مسار مكتبة JUnit على جهازك

add-junit.png.d036781d79b2a221002d50490a8ceb85.png

 

  • النتيجة, كلاس جاهزة انشئت لكتابة الاختبارات في المجلد التي قمت بتخصيصة

ready-to-right-tests.png.5857a173dd88d8aeeb3d337d4ac594ae.png

 

الـ Assertions في الـ JUnit

يأتي مع الـ JUnit دوال تسمى Assertions من خلالهم تستطيع اجراء الاختبارات, ويجب عليك حفظ وفهم هذه الدوال, كما هو الحال مع الـ Annotations. يمكنك الاطلاع عليهم من خلال هذا الرابط.

اهم هذه الدوال هي:

assertions.png.a1eb6ae7ff01330a742dd0fcf491c5da.png

 

شرح المشروع

قبل كتابة الاختبارات لنفهم هذا المشروع قليلاً. فأسم المشروع هو KidCalculator. وتستطيع ايجاد نسخة منه على رابط الجيت هوب لدي.

يتكون من عدة كلاسات (حالياً) وهي:

  • Main.java وهي الكلاس الرئيسية للمشروع.
  • MainTest.Java وهي كلاس الاختبارات التي انشئناها بالخطوات السابقة.
  • Calculator.Java وهي عبارة عن Model لكلاس الحاسبة لدينا, تحتوي على دوال الحاسبة كالجمع والطرح والقسمة والضرب الخ... والتي من خلالها سيبنى المشروع.
  • BigNumberException كلاس exception خاص بالمشروع, حتى نستخدمها لاحقاً.

سيكون عملنا فقط كتابة اكواد داخل كلاس الـ MainTest.Java بما ان الاختبارات هي الهدف من هذه المقالة.

 

كتابة الاختبارات

  • اولاً لنلقي نظرة على كلاس الـ Calculator حتى نفهم هذه الموديل

package com.company;

public class Calculator {
    private String mColor;
    private boolean mPower;

    public Calculator(String color) {
        mColor = color;
    }

    public String getColor() {
        return mColor;
    }

    public void setColor(String color) {
        mColor = color;
    }

    public boolean checkPower() {
        return mPower;
    }

    public void setOn() {
        mPower = true;
    }

    public void setOff() {
        mPower= false;
    }


    public int addition(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
    }

    public int subtraction(int firstNumber, int secondNumber) {
        return firstNumber - secondNumber;
    }

    public int multiplication(int firstNumber, int secondNumber) {
        return firstNumber * secondNumber;
    }

    public int division(int firstNumber, int secondNumber) {
        return firstNumber / secondNumber;
    }
}

 

  • والان لنقم بكتابة الاختبارات لهذه الموديل لإختبار المنطق في اجراء العمليات الحسابية حسب ماتم برمجته في الكود السابق.

package com.company;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class MainTest {

    private Calculator calculator;

    @Before
    public void setUp() {
        calculator = new Calculator("Red");
    }

    @Test
    public void addition_test() {
        int result = calculator.addition(2, 2);
        assertEquals(result, 4);
    }

    @Test
    public void subtraction_test() {
        int result = calculator.subtraction(10, 4);
        assertEquals(result, 6);
    }

    @Test
    public void multiplication_test() {
        int result = calculator.multiplication(5, 5);
        assertEquals(result, 25);
    }

    @Test
    public void division_test() {
        int result = calculator.division(10, 2);
        assertEquals(result, 5);
    }

}

 

ملاحظات:

  • استخدمنا هنا assertEquals وهي عباره عن دالة JUnit تاخد قيمة متوقعة (result) ثم تقارنها بالقيمة الحقيقة اي الصحيحة.
  • قمنا بأنشاء عنصر من موديل حاسبتنا Calculator في دالة الـ setUp والتي تعمل قبل كل الدوال حتى تنشئ عنصرنا ونتمكن من استخدامه في باقي دوال الاختبارات.

وتشغيل هذه الاختبار من خلال الضغظ بالزر الايمن على اسم الكلاس واختيار Run 'MainTest' او من خلال الايقونة الصغيره الخضراء كشكل السهم المستدير بجانب اسم الكلاس, كما بالصورة التالية:

how-to-run-tests.png.7c7f77f495f006c2e57549b9ead1e60b.png

 

نتيجة الاختبار

all-tests-passed.png.56cefb7d900b1162822f94381cbea635.png

نجاح جميع الاختبارات كما هو متوقع.

ملاحظة: لاتعير اهتمام للسطر الاحمر فهو خلل برمجي في الجافا, يحدث للماك وهذه اقتباس من احد العاملين بشركة اوراكل:

اقتباس

The message is benign, there is no negative impact from this problem since both copies of that class are identical (compiled from the exact same source). It is purely a cosmetic issue.

 

المزيد من الاختبارات

سوف نقوم بانشاء دالة تغير لون حاسبتنا وتتأكد من تغيير اللون. و أيضاً سنقوم بانشاء دالة اخرى تتاكد من هذا اللون, ثم نشغل جميع الدوال.

first-fail.thumb.png.79891f12197f480fb08f7bca3809cd77.png

 

ملاحظات:

  • قمنا بكتابة و تشغيل ٦ اختبارات, ٥ نجحو, وواحد فشل.
  • المهم هو ان الدالة check_color_and_change_it_test قد نجحت في تغيير اللون, ونجحت ايضاً في التأكيد من ان اللون قد تغير الى الازرق.
  • اما الدالة check_color_is_still_changed قد فشلت في التأكيد من ان اللون قد اصبح ازرق؟ لماذا؟ اليست الدالة التي قبلها قد قامت بتغيير هذا اللون؟

 

اقتباس

هذه النقطة هي من اكثر الامور تشتيت في الـ JUnit. وهي ان كل دالة معلمة بالنوتيشن Test تعتبر منفصلة عن اخواتها, هي فقط تتشارك مع الدوال كـ setUp المعلمة بالـ Before وغيرها.

هل تتذكر ان دالة الـ setUp و دالة الـ clean يتكرر تشغيلهم لكل دالة ذي نوتيشن Test في المثال الاول؟

اذن مع تشغيل هذه الدوال الاختبارية الـ ٦, نستطيع القول كاننا قمنا بتشغيل ٦ كلاسات منفصلة عن بعضها البعض!

اتمنى ان فهم هذه النقطة وصل, لان هذا الشئ يخلق مشاكل كثيرة في كتابة الاختبارات في المستقبل.


وهكذا قمنا بأنشاء مجلد اختبارات + انشاء كلاس اختبارات + كتابة ٦ دوال اختبارات باستخدام بعض من الـ Annotations و Assert واحده وهي assertEquals. واتوقف هنا حتى لايصبح للقارئ overwhelming و burnout, واكمل في المقالات اللاحقة ان شاء الله.

كلمات دليلية:
3
إعجاب
1128
مشاهدات
0
مشاركة
1
متابع
متميز
محتوى رهيب

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !