{ اختبار البرمجيات - Software Testing }

تفعيل ميزة الاختبار التلقائي للأعلام الوظيفية “Automating Feature Flag Testing”

ما هي الأعلام الوظيفية (Feature Flag)، ولماذا هي مهمة؟

الأعلام الوظيفية (Feature Flags)، المعروفة أيضًا بال toggle الوظيفية، هي أداة قوية في تطوير البرمجيات تتيح للفرق التحكم في تفعيل ميزات معينة دون الحاجة إلى نشر رمز جديد. عبر تشغيل الميزات أو إيقافها ديناميكيًا، يمكن للمطورين تقديم وظائف جديدة تدريجيًا، إجراء اختبارات A/B، أو إدارة الميزات التجريبية في بيئات مختلفة.

في جوهرها، تعمل الأعلام الوظيفية كشرطية داخل قاعدة الكود. على سبيل المثال، قد يحدد العلم الوظيفي ما إذا كان المستخدمون سيرون تصميم الصفحة الرئيسية الجديد أو يستمرون في التفاعل مع التصميم القديم. يتم التحكم بهذه الأعلام عادة عبر ملفات التكوين، واجهات برمجة التطبيقات (APIs)، أو منصات إدارة الأعلام مثل LaunchDarkly أو Flagsmith، مما يجعلها مرنة وسهلة الإدارة.

مقارنة بين وظائف التطبيق مع وضع علامة الميزة OFF (على اليسار) وON (على اليمين)


لماذا تعتبر الأعلام الوظيفية مهمة Feature Flag؟

  • النشر المتحكم به: تتيح الأعلام للفرق طرح الميزات لمجموعات معينة من المستخدمين أو في بيئات محددة، مما يقلل من مخاطر الفشل.
  • اختبارات A/B: تتيح اختبار نسخ متعددة من ميزة ما وقياس تفاعل المستخدم قبل اعتماد النسخة النهائية.
  • تجارب سريعة: يمكن للمطورين تجربة أفكار جديدة مع الحفاظ على استقرار بيئة الإنتاج.
  • التراجع السريع: إذا تسببت ميزة في مشاكل، يمكن إيقافها فورًا دون الحاجة إلى نشر جديد.


التحديات التي تواجه فرق ضمان الجودة

في حين أن الأعلام الوظيفية مفيدة للتطوير، فإنها تُضيف تعقيدًا لفرق ضمان الجودة. يجب على المختبرين التأكد من أن الميزات تعمل كما هو متوقع سواء كانت نشطة أو معطّلة. كما يمكن أن تؤثر الأعلام على موثوقية الاختبارات إذا لم تكن حالات الأعلام متسقة عبر البيئات.



إعداد اختبارات مدركة لحالة الأعلام

في عالم الأعلام الوظيفية، قد يؤدي تشغيل الاختبارات تلقائيًا دون مراعاة حالة العلم إلى نتائج غير متسقة وهدر للموارد. الاختبارات المدركة لحالة الأعلام هي الحل.


ما هي الاختبارات المدركة لحالة الأعلام؟

الاختبارات المدركة لحالة الأعلام مصممة للتحقق من حالة العلم الوظيفي قبل تنفيذ الاختبار. إذا كان العلم نشطًا، يتم التحقق من الوظيفة الجديدة. وإذا كان معطّلًا، يتم إما تخطي الاختبار أو التأكد من أن الميزة غير مرئية.


خطوات تنفيذ الاختبارات المدركة لحالة الأعلام

1. استرداد حالة العلم الوظيفي

استخدام API أو التكوين البيئي لتحديد حالة العلم:

async function getFeatureFlag(flagName) {  
  const response = await fetch(`https://feature-flags/status?flag=${flagName}`);  
  const data = await response.json();  
  return data.enabled;  
}


2. تنفيذ الاختبار بشكل شرطي

بناءً على حالة العلم، يتم اتخاذ قرار بشأن تشغيل الاختبار:

const { test } = require('@playwright/test');  

test('اختبار الميزة الجديدة', async ({ page }) => {  
  const featureEnabled = await getFeatureFlag('new_feature');  
  if (featureEnabled) {  
    await page.goto('https://example.com/new-feature');  
    await page.getByTestId('new-feature-button').click();  
    const message = await page.locator('#feature-result').textContent();  
    expect(message).toBe('Feature works!');  
  } else {  
    test.skip('الميزة غير مفعّلة، يتم تخطي الاختبار.');  
  }  
});


متى تستخدم هذه الاختبارات؟

  • في البيئات الديناميكية حيث تتغير حالة الأعلام باستمرار.
  • في حالات النشر الجزئي.
  • عند اختبار الميزات التجريبية.


اختبار كلا السيناريوهين: حالة التفعيل والإيقاف

الأعلام الوظيفية تخلق حالتين منفصلتين:

  1. عند تفعيل الميزة: التحقق من الوظائف الجديدة.
  2. عند تعطيل الميزة: ضمان استقرار التطبيق وخلوّه من أي آثار جانبية.


الخيار 1: الاختبارات المتعددة (Parameterized Tests)

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

const scenarios = [  
  { state: "enabled", flagValue: true },  
  { state: "disabled", flagValue: false },  
];  

scenarios.forEach(({ state, flagValue }) => {  
  test(`الميزة ${state}: التحقق من السلوك`, async ({ page }) => {  
    await setFeatureFlag("new_feature", flagValue);  
    await page.goto("https://example.com");  

    if (flagValue) {  
      await page.getByTestId("new-feature-button").click();  
      const result = await page.locator("#feature-result").textContent();  
      expect(result).toBe("Feature works!");  
    } else {  
      await expect(page.getByTestId("new-feature-button")).not.toBeVisible();  
    }  
  });  
});


الخيار 2: مجموعات اختبارات منفصلة

يمكن إنشاء مجموعات منفصلة للاختبار:

test.describe("الميزة مفعّلة", () => {  
  test.beforeEach(async () => {  
    await setFeatureFlag("new_feature", true);  
  });  

  test("التحقق من الوظيفة الجديدة", async ({ page }) => {  
    await page.goto("https://example.com");  
    await page.getByTestId("new-feature-button").click();  
    const result = await page.locator("#feature-result").textContent();  
    expect(result).toBe("Feature works!");  
  });  
});  


أتمتة تحديث الأعلام الوظيفية

تحديث الأعلام يدويًا قد يكون مضيعة للوقت. أتمتة العملية تضمن حالات اختبار متسقة:

استخدام واجهة برمجة التطبيقات (API):

async function setFeatureFlag(flagName, isEnabled) {  
  const response = await fetch('https://feature-flags/update', {  
    method: 'POST',  
    headers: { 'Content-Type': 'application/json' },  
    body: JSON.stringify({ flag: flagName, enabled: isEnabled })  
  });  
  if (!response.ok) {  
    throw new Error(`فشل تحديث العلم: ${flagName}`);  
  }  
}


استخدام التخزين المحلي:

test('تحديث العلم عبر Local Storage', async ({ page }) => {  
  await page.goto('https://example.com');  
  await page.evaluate(() => {  
    const flags = JSON.parse(localStorage.getItem('featureFlags') || '{}');  
    flags['new_feature'] = true;  
    localStorage.setItem('featureFlags', JSON.stringify(flags));  
  });  
  await page.reload();  
  await expect(page.getByTestId("new-feature-button")).toBeVisible();  
});


توضيح لغة الكود المستخدمة:

لغة الكود المستخدمة في الأمثلة المذكورة هي JavaScript، وتحديدًا مع Playwright، وهي أداة اختبار آلية تُستخدم لاختبار واجهات المستخدم في التطبيقات الحديثة عبر المتصفحات المختلفة.

توضيح الأدوات والبيئة:

  • JavaScript: لغة البرمجة الأساسية في الأمثلة.
  • Playwright: مكتبة اختبار آلي مفتوحة المصدر تُستخدم لاختبار التطبيقات على الويب عبر المتصفحات (مثل Chrome، Firefox، وEdge).
  • Node.js: البيئة التي يتم فيها تشغيل الكود المكتوب بلغة JavaScript.
  • Fetch API: تُستخدم لإجراء طلبات HTTP للحصول على بيانات من واجهات برمجة التطبيقات (APIs).
  • Local Storage: لتخزين البيانات محليًا في المتصفح وتحديث حالات الأعلام الوظيفية أثناء الاختبارات.


الخلاصة

تُعد الأعلام الوظيفية أدوات فعالة لإدارة النشر والتجارب. من خلال دمج اختبارات مدركة لحالات الأعلام وأتمتة تحديثاتها، يمكن ضمان تغطية شاملة وتقليل المخاطر. عند تنفيذ هذه الاستراتيجيات، ستتحول الأعلام الوظيفية إلى أصل يدعم جودة البرمجيات بدلاً من أن تكون عقبة.

مقالات ذات صلة

زر الذهاب إلى الأعلى