استخدام الـ Suites و Categories في الـ JUnit للتحكم في تشغيل الاختبارات

Mohammad Laifمنذ 6 سنوات

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

في هذه المقالة سنتعلم كيفية استخدام الـ Suites و Categories للتحكم في تشغيل الاختبارات حتى يتمكن المبرمج من التحكم بشكل ادق في ادارة و تشغيل اي من الاختبارات كما يتطلب الوضع, وبما انهم متشابهان في الوظيفة فأرى من الافضل التطرق لهم في مقالة واحدة.

 

المواضيع السابقة (مهمة لفهم هذا المقال)

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

https://3alam.pro/articles/android/junit-in-java/https://3alam.pro/articles/java/junit-in-java-part2/https://3alam.pro/articles/java/junit-junitmatchers/https://3alam.pro/articles/java/junit-rules/

 

رابط المشروع

https://github.com/mzdhr/KidCalculator-JUnit

وتوجد كلاسات هذه المقالة باسم: AdditionTest.class و SubtractionTest.class و MultiplicationTest.class و DivisionTest.class و AllMathematicalTest.java و MathematicalSuiteCategoriesTest في المشروع. واذا اردت الاطلاع على كلاس الـموديل فهذه هي Calculator.java.

 

ماذا سوف تقرئ في هذه المقالة
متى تستخدم الـ Suite, وكيفية انشاء مشغل Suites؟ متى تستخدم الـ Category, وطريقة انشاء فئة Category, وكيفية انشاء مشغل Category؟ واخيراً ماهو الفرق بين الـ Suite و Category؟

 

استخدام Suites في الـ JUnit
نستخدم الـ Suite اذا كانت لدينا الكثير من كلاسات الاختبارات ونريد تشغيلهم في اّن واحد. تخيل ان لديك ٥٠ كلاس اختبار (امر محتمل جداً في المشاريع الحقيقه) فتشغيل هذه الكلاسات واحده بعد الاخرى يدوياً متعب جداً. ماذا لو تريد فقط تشغيل ٣٠ كلاس متفرقه منهم في كل مره تعمل تحديث لشفرة مشروعك كإظافة ميزه ما؟ فقرائة اسمائهم والتشغيل اليدوي لهم يعتبر متعب جداً, اذن مالحل؟ الحل هو انشاء Suite يقوم بضم جميع هذه الكلاسات, وحينها تحتاج فقط لتشغيل هذا الـ Suite.

 

انشاء المزيد من كلاسات الاختبارات

كلاساتنا السابقه لاتكفي! لذلك سنقوم بكتابة المزيد من الكلاسات حتى نطبق عليهم الـ Suite. والطريقة سهله جداً, فقط نقوم بإنشاء كلاسات جديده بجانب الكلاس الرئيسية (MainTest.java) وكتابة الاختبارات بهم.

 

ماذا سننشئ؟

سننشئ اربعة كلاسات, كل كلاس تقوم بإختبار دالة (الجمع, الطرح, الضرب, القسمة) من الموديل Calculator بشكل اعمق, وهم كالتالي.

 

ومحتواهم كالتالي:

كلاس الـ AdditionTest.class


package com.company;

import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import static org.junit.Assert.assertEquals;

public class MathematicalAdditionTest {

    // Fields
    private Calculator calculator;

    @Before
    public void setUp() {
        // Arrange
        calculator = new Calculator("Orange");
    }

    @Test
    public void addition_a_test(){
        // Action
        int result = calculator.addition(6, 6);
        // Assert
        assertEquals(result, 12);    // is result actually equal 12?
    }

    @Test
    public void addition_b_test(){
        // Action
        int result = calculator.addition(-1, 8);
        // Assert
        assertEquals(result, 7);    // is result actually equal 7?
    }

    @Test
    @Category({CategorySlowTest.class})     // Marking this Test as CategorySlowTest, you can add more Categories too.
    public void addition_c_test(){
        // Action
        int result = calculator.addition(-1, -1);
        // Assert
        assertEquals(result, -2);    // is result actually equal -2?
    }
}

 

كلاس الـ SubtractionTest.class


package com.company;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class MathematicalSubtractionTest {

    // Fields
    private Calculator calculator;

    @Before
    public void setUp() {
        // Arrange
        calculator = new Calculator("Yellow");
    }

    @Test
    public void subtraction_a_test(){
        // Action
        int result = calculator.subtraction(6, 7);
        // Assert
        assertEquals(result, -1);    // is result actually equal -1?
    }

    @Test
    public void subtraction_b_test(){
        // Action
        int result = calculator.subtraction(-1, -5);
        // Assert
        assertEquals(result, 4);    // (-1) - (-5) = 4?
    }

    @Test
    public void subtraction_c_test(){
        // Action
        int result = calculator.subtraction(10, 4);
        // Assert
        assertEquals(result, 6);    // is result actually equal 6?
    }

}

 

كلاس الـ MultiplicationTest.class


package com.company;

import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import static org.junit.Assert.assertEquals;

@Category(CategorySlowTest.class)
public class MathematicalMultiplicationTest {

    // Fields
    private Calculator calculator;

    @Before
    public void setUp() {
        // Arrange
        calculator = new Calculator("Brown");
    }

    @Test
    public void multiplication_a_test(){
        // Action
        int result = calculator.multiplication(6, 6);
        // Assert
        assertEquals(result, 36);    // is result actually equal 36?
    }

    @Test
    public void multiplication_b_test(){
        // Action
        int result = calculator.multiplication(-1, 5);
        // Assert
        assertEquals(result, -5);    // is result actually equal -5?
    }

    @Test
    public void multiplication_c_test(){
        // Action
        int result = calculator.multiplication(-4, -4);
        // Assert
        assertEquals(result, 16);    // is result actually equal 16?
    }
}

 

كلاس الـ DivisionTest.class


package com.company;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class MathematicalDivisionTest {

    // Fields
    private Calculator calculator;

    @Before
    public void setUp() {
        // Arrange
        calculator = new Calculator("Purple");
    }

    @Test
    public void division_a_test(){
        // Action
        int result = calculator.division(12, 6);
        // Assert
        assertEquals(result, 2);    // is result actually equal 2?
    }

    @Test
    public void division_c_test(){
        // Action
        int result = calculator.division(10, -2);
        // Assert
        assertEquals(result, -5);    // is result actually equal -5?
    }
}

 

انشاء مشغل (Runner) اجنحة (Suites)

والان سننشئ مشغل لكل هذه الكلاسات, والذي من خلال تشغيله يقوم بتشغيل جميع الاختبارات الموجودة بهذه الكلاسات الاربعه جميعاً.

ماهو المشغل؟

المشغل عبارة عن كلاس عادية نقوم باستخدام النوتيشن RunWith فوقها, ثم نحدد نوع المشغل المراد بداخل هذه النوتيشن وهو Suite في حالتنا هذه. ثم نحدد لهذا الـ Suite الكلاسات المراد ضمها.

كود كلاس مشغل الـ Suite


package com.company;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

// This is the important part, which is annotations this class.
@RunWith(Suite.class)
@Suite.SuiteClasses({
        // List all test classes you want to run them in one time
        MathematicalAdditionTest.class,
        MathematicalSubtractionTest.class,
        MathematicalMultiplicationTest.class,
        MathematicalDivisionTest.class
})

// Empty class
public class MathematicalSuiteAllTest {
}

تعقيب

قمنا بجعل هذه الكلاس AllMathematicalTest.java مشغل (Runner) بدلاً من المشغل الافتراضي الذي يأتي مع الـ JUnit. وذلك بتعليمها بالنوتشن RunWith. ثم بتحديد نوع المشغل الذي نريده وهو Suite.class وهكذا اصحبت مشغل اجنحه Suite. ثم نقوم بكتابة جميع الكلاسات المراد تشغيلها بداخل النوتيشن SuiteClasses. ونستطيع انشاء عناصر منها كمشغلات في اكوادنا لاحقاً اذا دعت الحاجة لذلك.

 

تشغيل مشغل الـ Suite

اسرع خيار لتشغيله هو من خلال الضغظ على السهم الدائري بجانب اسم الكلاس, كما بالصوره التالي:

junitsuiterunnerhow.png.0956edfad28d78e075c9a12197b01485.png

 

نتيجة تشغيل مشغل الـ Suite

junitsuiterun.thumb.png.8611440c533c03b09bff731b5aec0d82.png

تعقيب

قبل كل شئ لاتهتم للنص ذي الون الاحمر! فهو خطئ يحدث فقط في نظام الماك ولا يؤثر بشئ. الان نرى من تشغيل هذا المشغل انه قام بتشغيل جميع الاختبارات بداخل الكلاسات الاربع, كما هو واضح بالصوره السابقه في جهة اليمين, وجميع اختباراتهم قد نجحوا.

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

 

 

استخدام Categories في الـ JUnit

نستخدم الـ Categories اذا كانت لدينا دوال اختبار متفرقه سواء بكلاسات عديدة او بنفس الكلاس ونريد تحديدهم ومن ثم تشغيلهم في وقت واحد وبضغطة زر واحده. فبعض الاحيان لانريد تشغيل كل دوال الاختبار في الكلاس بل فقط البعض منهم. فالـ Categories مشابه جداً لعمل الـ Suite, بل هو في الحقيقه مشغل Suite كالسابق ولكنه يمتاز عليه بانه يستطيع قرائة نوتيشن اسمه Category يوضع فوق دوال الاختبار.

 

انشاء فئات (Categories) خاصة بنا

حتى تستطيع استخدام هذا النوع من المشغلات, يجب علينا ان ننشئ فئاتنا الخاصه والتي من خلالهم سوف نقوم بتعليم اي دالة اختبار بما يناسبها حسب احتياجاتنا.

في هذا المشروع KidCalculator سنقوم بأنشاء فئتين Categories وهم كالتالي:

  • CategoryFastTest.java, وهي عباره عن انترفيس فارغة, سنحتاجها لتوسيم دوال الاختبار السريعه لدينا.
  • CategorySlowTest.java, وهي عباره عن انترفيس فارغة, سنحتاجها لتوسيم دوال الاختبار البطيئه لدينا.

 

كود الـ CategoryFastTest.java


package com.company;

public interface CategoryFastTest {
}

 

كود الـ CategorySlowTest.java


package com.company;

public interface CategorySlowTest {
}

 

انشاء مشغل (Runner) فئات (Categories)

الان سوف ننشئ مشغل الفئات (Categories). العملية مشابهه لإنشاء مشغل Suite ولكن الفرق هنا اننا سنقوم بإضافة نوتيشن مسؤول عن الفئات.

 

كود كلاس المشغل


package com.company;


import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Categories.class)
// This Runner runs only @Tests Methods that annotated with CategorySlowTest.java.
@Categories.IncludeCategory(CategorySlowTest.class)
// If you want to exclude any Category use:
// @Categories.ExcludeCategory(CategorySlowTest.class)
@Suite.SuiteClasses({
        MainTest.class,
        // Or we can use our last Suite -> MathematicalSuiteAllTest.class ...
        // ... that contains all these four classes:
        MathematicalAdditionTest.class,         
        MathematicalSubtractionTest.class,      
        MathematicalMultiplicationTest.class,
        MathematicalDivisionTest.class
})
public class MathematicalSuiteCategoriesTest {
}

تعقيب

قمنا بجعل هذه الكلاس MathematicalSuiteCategoriesTest مشغل (Runner) بدلاً من المشغل الافتراضي الذي يأتي مع الـ JUnit. وذلك بتعليمها بالنوتشن RunWith. ثم قمنا بتحديد نوع المشغل الذي نريده وهو Categories.class وهكذا اصبح مشغل فئات Categories. ومن ثم اضافة النوتيشن IncludeCategory واعطائه الفئه التي نريد منه ان يشغلها (اعطيناه الانترفيس السابقه التي انشئناها CategorySlowTest.java كفئه). ثم نقوم بكتابة جميع كلاسات الاختبار لدينا بداخل النوتيشن suiteClasses. ونستطيع انشاء عناصر منها كمشغلات في اكوادنا لاحقاً اذا دعت الحاجة لذلك.

 

وضع فئات لدوال الاختبارات

والان لنعلم بعض من دوال الاختبارات التي لدينا, بأضافة النوتيشن Category فوقها, ثم الاتيان بالفئه المراده (وهي التي انشئناها CategorySlowTest.java حتى نعلم هذه الدالة بانها بطيئه), كما بالكود التالي:


    @Test
    // Marking this Test as CategorySlowTest, you can add more Categories too.
    @Category({CategorySlowTest.class})
    public void addition_c_test(){
        // Action
        int result = calculator.addition(-1, -1);
        // Assert
        assertEquals(result, -2);    // is result actually equal -2?
    }

تعقيب

هذه الدالة موجودة بداخل الكلاس MathematicalAdditionTest.java. نحن قمنا بوضع النوتيشن Category فوقها, وتعليمها بانها دالة بطيئه باستخدام الفئه CategorySlowTest.java التي انشئناها سابقاً بداخل هذا النوتيشن.

 

وضع فئات لكلاس اختبارات بأكملها

وكذلك نستطيع وضع فئات على الكلاسات وليس فقط على الدوال, كما بالكود التالي:


@Category(CategorySlowTest.class)
public class MathematicalMultiplicationTest {

تعقيب

هذه الكلاس هي MathematicalMultiplicationTest.java. قمنا بوضع النوتيشن Category فوقها, وتعليمها بانها كلاس بطيئه باستخدام الفئه CategorySlowTest.java التي انشئناها سابقاً بداخل هذا النوتيشن.

 

تشغيل مشغل الـ Categories

اسرع خيار لتشغيله هو من خلال الضغظ على السهم الدائري بجانب اسم كلاسه, كما بالصوره التالي:

runcategoryrunner.png.89c87d221a541e2da582c694835572c1.png

 

نتيجة تشغيل المشغل Category

resultrunnercategory.thumb.png.6068e9b3cab87600f068d75444518306.png

تعقيب

نلاحظ ان الدالة addition_c_test التي قمنا بتعليمها بالنوتيشن Category ووضعنا فئتها: CategorySlowTest.java قد تم تشغيلها. وايضاً نلاحظ ان جميع دوال الكلاس MathematicalMultiplicationTest.java قد تم تشغيلهم وذلك بسبب وضع النوتيشن Category وتحديد فئة الكلاس بـ CategorySlowTest.java فوق اسم الكلاس.

والفائده من هذا هي اذا كان لدينا اي اختبار بطئ فنستطيع وضعه ضمن فئة الاختبارات البطيئه, ومن ثم التعديل على الشفره البرمجيه لمشروعنا ونعيد تشغيل هذه الاختبارات البطيئه لنرى هل اصبحت سريعه ام لا.

 

في النهاية تعلمنا كيفية استخدام مشغلات الـ Suite و Category وكيفية انشائهم, وهذا يعتبر شئ مهم عندما تريد التحكم في تشغيل اي من الاختبارات.

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

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

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

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