كتابة اختبارات الـ JUnit بشكل مستحسن
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته
هذه المقالة لتعلم كيفية كتابة اختبارات JUnit للغة الجافا بشكل مرتب وسلس حتى يشعر القارئ بالراحة وعدم الضياع في كلاس الاختبارات.
هذا الموضوع عبارة عن تكملة للموضوع الرئيسي:
كتابة اختبارات الـ JUnit بشكل محترف
توجد اتفاقية (Conventions) لكتابة الاختبارات بشكل محترف لدى المبرمجين, حتى يسهل عليهم قرائتها والتعامل معها. وهذه الطريقة تسمى اختصاراً بالـ AAA. و ايضاً سأقوم بالتطرق الى بعض الملاحظات والتحذيرات عند كتابة دوال الاختبارات.
AAA Style for Tests
وتتكون هذه الطريقة من ثلاثة اقسام وهم:
- الـ Arrange (الترتيب) اي ترتيب وتجهيز العناصر لإجراء الاختبارات عليها.
- الـ Action (الفعل) اي السلوك للعناصر المراد اختبارها "يعني الدوال للــ Object".
- الـ 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);
}
الناتج
تعقيب
هل تستطيع تحديد اي من الخوارزميات الخاطئة في المنطق؟ هل هي 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);
}
الناتج
تعقيب
من الصورة نرى ان الخوارزمية 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?
}
}
وهكذا تصبح قرائة الاختبارات اكثر سهولة وكتابتها ايضاً.
التعليقات (0)
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !