كتابة اختبارات الـ JUnit بشكل مستحسن

Mohammad Laifمنذ 6 سنوات

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

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

 

هذه المقالة لتعلم كيفية كتابة اختبارات JUnit للغة الجافا بشكل مرتب وسلس حتى يشعر القارئ بالراحة وعدم الضياع في كلاس الاختبارات.

هذا الموضوع عبارة عن تكملة للموضوع الرئيسي: 

https://3alam.pro/index.php/forums/topic/380-%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%80-junit-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%AC%D8%A7%D9%81%D8%A7/

كتابة اختبارات الـ JUnit بشكل محترف

توجد اتفاقية (Conventions) لكتابة الاختبارات بشكل محترف لدى المبرمجين, حتى يسهل عليهم قرائتها والتعامل معها. وهذه الطريقة تسمى اختصاراً بالـ AAA. و ايضاً سأقوم بالتطرق الى بعض الملاحظات والتحذيرات عند كتابة دوال الاختبارات.

AAA Style for Tests

وتتكون هذه الطريقة من ثلاثة اقسام وهم:

  1. الـ Arrange (الترتيب) اي ترتيب وتجهيز العناصر لإجراء الاختبارات عليها.
  2. الـ Action (الفعل) اي السلوك للعناصر المراد اختبارها "يعني الدوال للــ Object".
  3. الـ Assert (التأكيد او الجزم) في هذه المرحلة نكتب الكود الذي من خلاله نتحقق من صحة المنطق لدينا.

مثال


    @Test
    public void setting_calculator_color_test(){
        // Arrange
        Calculator calculator = new Calculator("none");

        // Action
        calculator.setColor("blue");

        // Assert
        assertEquals(calculator.getColor(), "blue");
    }

التعقيب

  • الترتيب: قمنا بانشاء عنصر حاسبة من موديل الـ Calculator.
  • الفعل: قمنا بالنداء على الدالة setColor() لتحويل الحاسبة الى اللون الازرق.
  • التأكيد: قمنا بكتابة شفرة الجزم المطلوبة باستخدام assertEquals, والذي من خلالها سنجزم ان لون حاسبتنا اصبح ازرق حتى ينجح الاختبار, والا فأن الفعل setColor به خلل منطقي.

والان حتى لانكرر انشاء العنصر calculator كل مرة نقوم بكتابة دالة اختبار. فالافضل ان نحوله الى Field. ثم نقوم بكتابة الدالة setUp ذي النوتيشن Before والتي فيها ننشئ عناصرنا.
 

لتصبح دالة الاختبار بهذا الشكل:


    @Test
    public void setting_calculator_color_test(){
        // Action
        calculator.setColor("blue");

        // Assert
        assertEquals(calculator.getColor(), "blue");
    }

 

اما باعلى الكلاس فالوضع اصبح هكذا:


public class MainTest {

    // Fields
    private Calculator calculator;

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

تحذير: لاتقم باختبار فعلين في دالة واحده

مثال


    @Test
    public void subtraction_multiplication_tests(){
        // Action & Assert
        assertEquals(calculator.subtraction(10, 6), 4);     // is 10 - 6 = 4 ?
        assertEquals(calculator.multiplication(6, 2), 12);  // is 6 * 2 is 12 ?
    }

تعقيب

كتابة الاختبارات بهذا الشكل خاطئ جداً! لماذا؟

لاننا قمنا باختبار فعلين مختلفين وهم substraction() و multiplications() في دالة واحدة وهذا غير مستحسن. ففي حالة فشل هذا الاختبار فأننا لاندري اي فعل هو المسبب للفشل, وسيكون الـ debug صعب جداً بل مربك. فمن الافضل ان نقوم باختبار فقط فعل واحد في كل دالة اختبار قدر المستطاع. اذن لنضع على هذه الداله النوتيشن Ignore حتى يتجاهلها الـ JUnit

مثال اخر

اختبار خوارزمية القسمة العادية و خوارزمية القسمة المطولة في نفس الدالة.


    @Test
    public void divisions_test(){
        // Action & Assert
        assertEquals(calculator.division(100, 2), 50);
        assertEquals(calculator.longDivision(100, 2), 50);
    }

الناتج

divisions_test.thumb.png.599412851aea3795bfd30e1f480c8884.png

تعقيب

هل تستطيع تحديد اي من الخوارزميات الخاطئة في المنطق؟ هل هي division ام longDivision ؟ هل رأيت صعوبة الامر للقارئ.

الحل

هو فصل الفعلين الى دالتين اختبار منفصلتين. ولكن الم تلاحظ تقارب بين الفعلين؟ القسمة العادية والقسمة المطولة؟ فهنا نستطيع المحافظة عليهم في نفس دالة الاختبار ونقوم بإظافة رسالة تسهل علينا الأمر في حالة التعطل.

الحل هو بأضافة تعليق لكل سطر تأكيد في الداله كما التالي:


    @Test
    public void divisions_test(){
        // Action & Assert
        assertEquals("Normal Division", calculator.division(100, 2), 50);
        assertEquals("Long Division", calculator.longDivision(100, 2), 50);
    }

الناتج

divisionserror.thumb.png.542b4f3889d8c79dcdc0b4946cd51d40.png

تعقيب

من الصورة نرى ان الخوارزمية Long Division هي السبب لفشل الاختبار. وهكذا اصبح على القارئ و المبرمج اكتشاف الاخطاء اسهل بكثير.

الكلاس كاملة


package com.company;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import static org.junit.Assert.*;

public class MainTest {

    // Fields
    private Calculator calculator;

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

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

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

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

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

    @Test
    public void check_color_and_change_it_test(){
        // Action
        if (calculator.getColor().equals("Red")){
            calculator.setColor("Blue");
        }
        // Assert
        // Check is color changed?
        assertEquals(calculator.getColor(), "Blue");
    }

    @Ignore
    @Test
    public void check_color_is_still_changed(){
        // Assert
        assertEquals(calculator.getColor(), "Blue");
    }


    // --------------------------- //
    // --- New Tests - Part 02 --- //
    // --------------------------- //

    @Test
    public void setting_calculator_color_test(){
        // Action
        calculator.setColor("blue");

        // Assert
        assertEquals(calculator.getColor(), "blue"); // is calculator color actually blue?
    }

    @Ignore
    @Test
    public void subtraction_multiplication_tests(){
        // Action & Assert
        assertEquals(calculator.subtraction(10, 6), 4);     // is 10 - 6 = 4 ?
        assertEquals(calculator.multiplication(6, 2), 12);  // is 6 * 2 is 12 ?
    }

    @Test
    public void divisions_test(){
        // Action & Assert
        assertEquals("Normal Division", calculator.division(100, 2), 50);
        assertEquals("Long Division", calculator.longDivision(100, 2), 50);
    }

    @Test
    public void calculator_is_not_null_test(){
        // Assert
        assertNotNull(calculator);
    }

    @Test
    public void check_calculator_power_test(){
        // Assert & Action
        assertTrue(calculator.checkPower());    // is calculator is powered on?
    }


}

 

وهكذا تصبح قرائة الاختبارات اكثر سهولة وكتابتها ايضاً.

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

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

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

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