عزل الاختبارات والتنفيذ المتوازي

عزل الاختبارات (Test Isolation) يعني أن يعطي الاختبار النتيجة نفسها سواء شُغّل وحده أو بأي ترتيب أو عدة مرات أو في اللحظة نفسها مع اختبارات أخرى، لأنه يبني الحالة التي يحتاجها ولا يعتمد على شيء يتركه اختبار آخر. والتنفيذ المتوازي (Parallel Execution) يعني أن يشغّل مشغّل الاختبارات عدة اختبارات في وقت واحد: في عمّال (workers) منفصلين على جهاز واحد، أو في أجزاء (shards) موزّعة على عدة أجهزة. فحزمة اختبارات لإتمام الشراء تستغرق ⁦24⁩ دقيقة بعامل واحد قد تنتهي في ربع هذا الوقت تقريباً بأربعة عمّال، بشرط ألا يستخدم اختباران الحساب أو السلة أو الملف نفسه في اللحظة نفسها.

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

لماذا يهم

الاختبارات التي يعتمد بعضها على بعض تعطي نتائج لا يثق بها أحد. ينجح اختبار في التشغيل الكامل فقط لأن اختباراً سابقاً أنشأ الطلب الذي يقرؤه، ثم يفشل حين يشغّله أحد وحده أو يضيف عاملاً؛ ويعدّل اختباران المستخدم نفسه في اللحظة نفسها فيفشل أحدهما مرة في كل عشرين تشغيلاً. حالات الفشل هذه تبدو كأنها عيوب في المنتج، وتكلّف ساعات من التحقيق، وتعلّم الفريق إعادة تشغيل البناءات الحمراء بدلاً من قراءتها. ويعدّ Martin Fowler غياب العزل سبباً شائعاً للاختبارات غير الحتمية (non-deterministic).

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

العزل ومشكلات الحالة المشتركة

الاختبار المعزول يتحكم في حالة البداية الخاصة به: ينشئ ما يحتاجه أو يتسلّمه من تجهيزة (Fixture)، ولا يتحقق إلا من بيانات أنشأها بنفسه أو بيانات لا يغيّرها أي اختبار. وتطلب أفضل الممارسات في Playwright أن يعمل كل اختبار باستقلال، بتخزينه وملفات تعريف الارتباط (cookies) وبياناته الخاصة؛ وتعدّ Cypress اعتماد الاختبارات على حالة اختبارات سابقة نمطاً سيئاً (anti-pattern).

الحالة المشتركة (Shared State) هي أي شيء يستطيع اختبار تغييره ويستطيع اختبار آخر رؤيته. والبيانات المخصّصة للقراءة فقط، مثل كتالوج منتجات لا يعدّله أي اختبار، آمنة للمشاركة؛ أما الحالة المشتركة القابلة للتغيير فلا. والعلاج أن تعطي كل اختبار، أو كل عامل على الأقل، نسخته الخاصة مما يغيّره، وأن تبني هذه الحالة في بداية الاختبار. ويفضّل Martin Fowler إعادة بناء حالة البداية على الاعتماد على التنظيف: فحين يفشل التنظيف يفشل اختبار آخر بعيداً عن الخلل. وتختبئ الحالة المشتركة القابلة للتغيير في خمسة أماكن:

  • بيانات الخادم: حساب أو سلة أو طلب أو قسيمة واحدة تستخدمها اختبارات كثيرة. يفرّغ اختبار السلة التي يفحصها اختبار آخر، وقسيمة الاستخدام الواحد لا تعمل إلا للاختبار الذي يصل إليها أولاً.
  • الاعتماد على الترتيب: الاختبار B يقرأ الطلب الذي أنشأه الاختبار A. ينجح B بالترتيب المعتاد، ويفشل حين يُشغَّل وحده أو بترتيب عشوائي أو على عامل آخر.
  • الحالة في الذاكرة: متغير على مستوى الوحدة البرمجية (module)، أو كائن وحيد (singleton) يتشاركه البرنامج كله، أو ذاكرة تخزين مؤقت، أو ساعة مزيّفة، أو «مستخدم حالي» يضبطه اختبار ولا يعيد ضبطه. عمليات العمّال لا تتشارك الذاكرة، لكن الاختبارات داخل العامل الواحد تتشاركها، وكذلك الخيوط (threads) المتوازية في JUnit 5.
  • حالة المتصفح: ملفات تعريف الارتباط والتخزين المحلي وجلسة الدخول. وإعادة استخدام جلسة دخول محفوظة مناسبة للاختبارات التي تقرأ فقط؛ أما الاختبار الذي يسجّل الخروج أو يعدّل الملف الشخصي فيحتاج إلى جلسة خاصة به.
  • موارد الجهاز والبيئة: مسار ملف ثابت مثل downloads/report.csv، أو منفذ ثابت، أو صندوق بريد مشترك واحد، أو واجهة برمجية تجريبية (sandbox) محدودة المعدّل، أو علم ميزة (feature flag) على مستوى الموقع كله.

جرّبها: مولّد عناوين بريد إلكتروني وهمية

كيف تشغّل المشغّلات الاختبارات بالتوازي

في Playwright Test وJest وpytest-xdist، العامل (worker) عملية مستقلة في نظام التشغيل تشغّل الاختبارات واحداً بعد الآخر. ومع أربعة عمّال تعمل أربعة اختبارات في اللحظة نفسها. ذاكرتها منفصلة، لكن بيئة الاختبار وقاعدة بياناتها والملفات على القرص ومنافذ الشبكة ليست كذلك. وتختلف المشغّلات فيما تقسّمه افتراضياً، وفي طريقة منح كل عامل موارده الخاصة:

  • يشغّل Playwright Test ملفات الاختبار بالتوازي، وتعمل الاختبارات داخل الملف الواحد بالترتيب في العامل نفسه، إلا إذا ضبطت fullyParallel: true أو test.describe.configure({ mode: 'parallel' }). وتحدّد العدد بالخيار workers في الإعدادات أو بـ--workers. ويحصل كل اختبار على سياق متصفح (browser context) جديد، أي جلسة متصفح معزولة تشبه نافذة تصفح خاص جديدة، بملفات تعريف ارتباط وتخزين خاصة به، وبعد أي فشل يستبدل Playwright العامل بعملية جديدة.
  • يحتاج pytest إلى الإضافة pytest-xdist: الأمر pytest -n 4، أو -n auto لعامل واحد لكل معالج. وتعيد التجهيزة worker_id القيم gw0 وgw1 وهكذا.
  • يوزّع Jest ملفات الاختبار على عمليات عمّال، ويشغّل اختبارات الملف الواحد بالترتيب؛ والخيار --runInBand يشغّل كل شيء تسلسلياً في عملية واحدة.
  • يشغّل JUnit 5 الاختبارات تسلسلياً في خيط (thread) واحد افتراضياً. والتنفيذ المتوازي اختياري: معامل الإعداد junit.jupiter.execution.parallel.enabled=true يفعّله، لكن الاختبارات تظل تعمل واحداً بعد الآخر حتى تجعلها تعمل بالتوازي فعلاً، مثلاً بـjunit.jupiter.execution.parallel.mode.default=concurrent. والاختبارات المتوازية خيوط داخل JVM واحد، لذا تتشارك الحقول الساكنة (static) والكائنات الوحيدة. ويصرّح @ResourceLock بأن الاختبارات تستخدم مورداً مشتركاً يحتاج إلى وصول متزامن.
  • موارد لكل عامل: حين يتعذّر إنشاء شيء لكل اختبار، أعطِ كل عامل نسخته الخاصة. فقيمة testInfo.parallelIndex في Playwright تتراوح من ⁦0⁩ إلى عدد العمّال ناقص ⁦1⁩، فيأخذ العامل ⁦2⁩ الحساب ⁦2⁩ من مجموعة حسابات جُهّزت قبل التشغيل.
  • استثناءات تسلسلية: الاختبار الذي يغيّر شيئاً عاماً، مثل نسبة ضريبة القيمة المضافة أو علم ميزة على مستوى الموقع، لا يمكن أن يعمل بجانب اختبارات أخرى. انقله إلى تشغيل منفصل صغير بالخيار --workers=1، وجدوله بحيث لا يتزامن أبداً مع التشغيل الرئيسي على البيئة نفسها، بدلاً من جعل الحزمة كلها تسلسلية.

التقسيم إلى أجزاء: توزيع الحزمة على عدة أجهزة

يتشارك العمّال معالج الجهاز الواحد وذاكرته، لذا تتوقف إضافة العمّال عن الإفادة حين ينشغل الجهاز. أما التقسيم إلى أجزاء (Sharding) فيوزّع الحزمة على عدة أجهزة: تشغّل كل مهمة CI جزءاً واحداً، أي قسماً ثابتاً من الاختبارات، ويمكن لكل جزء أن يستخدم عدة عمّال. فالأمر npx playwright test --shard=2/4 يشغّل الجزء الثاني من أربعة، ويقبل Jest وVitest الخيار --shard نفسه.

التوازن هو ما يحدد المكسب، لأن التشغيل ينتهي حين ينتهي أبطأ جزء. فمن دون fullyParallel يوزّع Playwright ملفات كاملة على الأجزاء، فقد يُبقي ملف طويل واحد جزءاً مشغولاً بينما تنتظر الأجزاء الأخرى؛ ومعه تُوزَّع الاختبارات فرادى. وكل جزء لا يُبلغ إلا عن اختباراته: يكتب Playwright تقرير blob لكل جزء، وتدمجها مهمة أخيرة في تقرير واحد قبل أن يحكم أحد على التشغيل.

وللأجزاء خطر عزل خاص بها. فهي تعمل على أجهزة مختلفة لكنها غالباً تستخدم بيئة الاختبار نفسها، وأرقام العمّال تتكرر في كل جزء. لذلك فإن اسماً مثل qa+w0@example.com، أو الحساب ⁦0⁩ من مجموعة حسابات، يستخدمه أربعة عمّال في وقت واحد؛ أضف رقم الجزء، أو استخدم قيمة عشوائية مثل UUID.

# Four CI jobs start at the same time, one shard each
npx playwright test --shard=1/4 --reporter=blob
npx playwright test --shard=2/4 --reporter=blob
npx playwright test --shard=3/4 --reporter=blob
npx playwright test --shard=4/4 --reporter=blob

# A final job downloads the four blob reports into one folder and merges them
npx playwright merge-reports --reporter html ./all-blob-reports

جرّبها: مولّد UUID

مثال تطبيقي: ثلاثة اختبارات لا تفشل إلا بالتوازي

حزمة لإتمام الشراء من ⁦120⁩ اختباراً في المتصفح تستغرق ⁦24⁩ دقيقة بعامل واحد. يضبط الفريق fullyParallel: true وأربعة عمّال، فينخفض زمن التشغيل إلى ⁦7⁩ دقائق، لكن ثلاثة اختبارات صارت تفشل في بعض التشغيلات. وما زالت الحزمة كلها تنجح في كل مرة مع --workers=1، لذا فالسبب المرجّح تداخل بين الاختبارات لا عيب في المنتج.

كل الاختبارات تسجّل الدخول بالحساب qa.shared@example.com. يضيف اختبار «إجمالي السلة» منتجين بسعر ⁦150.00⁩ و⁦80.00⁩ ويتوقع ⁦230.00⁩، لكنه يرى أحياناً ⁦0.00⁩، لأن اختبار «تفريغ السلة» الذي يعمل على عامل آخر يفرّغ السلة نفسها. ويتوقع اختبار «سجل الطلبات» أن تعرض القائمة ثلاثة طلبات، هي التي تنشئها اختبارات الطلب الثلاثة في ملفه؛ ولم ينجح إلا لأنه كان يعمل بعدها في العامل نفسه، وهو يفشل حتى حين يُشغَّل وحده. ويحفظ اختبار «تنزيل الفاتورة» الملف في downloads/invoice.pdf، حيث قد تكتب فوقه فاتورة عامل آخر.

يشغّل عاملان اختباري «إجمالي السلة» و«تفريغ السلة» في اللحظة نفسها: مع حساب مشترك واحد تُفرَّغ السلة أثناء الاختبار فيظهر ⁦0.00⁩ بدل ⁦230.00⁩، ومع حساب لكل عامل ينجح الاختباران.
  • حساب مشترك واحد

    • العامل 1 اختبار «إجمالي السلة»
    • بيئة الاختبار سلة واحدة لكل الاختبارات
    • العامل 2 اختبار «تفريغ السلة»
    1. 1 من العامل 1 إلى بيئة الاختبار: إضافة منتجين بسعر ⁦150.00⁩ و⁦80.00⁩ qa.shared@example.com
    2. 2 من العامل 2 إلى بيئة الاختبار: تفريغ السلة في اللحظة نفسها الحساب نفسه، إذن السلة نفسها qa.shared@example.com
    3. 3 العامل 2 داخليًا: التأكيد: السلة فارغة نجاح
    4. 4 من العامل 1 إلى بيئة الاختبار: فتح السلة وقراءة الإجمالي
    5. 5 من بيئة الاختبار إلى العامل 1: يعرض إجمالياً قدره ⁦0.00⁩ ردّ
    6. 6 العامل 1 داخليًا: التأكيد: الإجمالي ⁦230.00⁩ فشل

    النتيجة: يفشل فقط حين يتزامن الاختباران؛ وكل منهما ينجح وحده ومع عامل واحد. فشل

  • حساب جديد لكل عامل

    • العامل 1 اختبار «إجمالي السلة»
    • بيئة الاختبار حساب وسلة منفصلان لكل عامل
    • العامل 2 اختبار «تفريغ السلة»
    1. 1 من العامل 1 إلى بيئة الاختبار: إضافة منتجين بسعر ⁦150.00⁩ و⁦80.00⁩ qa+3f9a…@example.com
    2. 2 من العامل 2 إلى بيئة الاختبار: تفريغ سلته الخاصة في اللحظة نفسها حساب مختلف، إذن سلة مختلفة qa+c41e…@example.com
    3. 3 العامل 2 داخليًا: التأكيد: السلة فارغة نجاح
    4. 4 من العامل 1 إلى بيئة الاختبار: فتح السلة وقراءة الإجمالي
    5. 5 من بيئة الاختبار إلى العامل 1: يعرض إجمالياً قدره ⁦230.00⁩ ردّ
    6. 6 العامل 1 داخليًا: التأكيد: الإجمالي ⁦230.00⁩ نجاح

    النتيجة: التوقيت نفسه وسلتان منفصلتان: ينجح الاختباران مهما تداخلت خطواتهما. نجاح

  • ينشئ كل عامل حساباً جديداً خاصاً به في تجهيزة على مستوى العامل، مع UUID في البريد الإلكتروني حتى لا تتصادم الأجزاء أيضاً.
  • الاختبارات داخل العامل الواحد ما زالت تتشارك هذا الحساب واحداً بعد الآخر، لذا يفرّغ الخطاف beforeEach السلة قبل كل اختبار بدلاً من الوثوق بالاختبار السابق.
  • ينشئ «سجل الطلبات» طلباته الثلاثة عبر الواجهة البرمجية (API) ويتحقق من معرّفاتها، لا من العدد الإجمالي.
  • تُحفظ الفاتورة في test.info().outputPath()، وهو مجلد فريد لكل اختبار.
  • يُتأكَّد من الإصلاح بالخيار --repeat-each=10 مع أربعة عمّال، لأن تشغيلاً أخضر واحداً لا يثبت الكثير.
// fixtures.ts: one fresh account per worker process
import { test as base } from '@playwright/test';
import { randomUUID } from 'node:crypto';

type Account = { id: string; email: string };

export const test = base.extend<{}, { account: Account }>({
  account: [async ({ playwright }, use) => {
    const api = await playwright.request.newContext({ baseURL: process.env.BASE_URL });
    const email = `qa+${randomUUID()}@example.com`;   // unique in every shard
    const res = await api.post('/api/test-accounts', { data: { email } });
    const account: Account = await res.json();
    await use(account);                                // shared by this worker's tests
    await api.delete(`/api/test-accounts/${account.id}`);
    await api.dispose();
  }, { scope: 'worker' }],
});

// cart.spec.ts
import { test } from './fixtures';

test.beforeEach(async ({ request, account }) => {
  await request.delete(`/api/test-accounts/${account.id}/cart`);   // start empty
});

test('download invoice', async ({ page, account }) => {
  // ...sign in as account.email and place an order...
  const downloading = page.waitForEvent('download');
  await page.getByRole('button', { name: 'Download invoice' }).click();
  await (await downloading).saveAs(test.info().outputPath('invoice.pdf'));
});

جرّبها: مولّد مستخدمين وهميين

أخطاء شائعة

  • تفعيل التنفيذ المتوازي دون التحقق أولاً مما تتشاركه الاختبارات، ثم لوم المشغّل على حالات الفشل التي يكشفها.
  • إصلاح الاعتماد على الترتيب بفرض ترتيب، عبر الوضع التسلسلي أو ترقيم أسماء الملفات، بدلاً من أن يبني كل اختبار حالته الخاصة.
  • استخدام رقم العامل وحده جزءاً فريداً في الاسم، فيستخدم العامل ⁦0⁩ في كل جزء الحساب نفسه.
  • التحقق من أعداد إجمالية مثل «القائمة فيها ثلاثة طلبات» في بيئة مشتركة بدلاً من التحقق من السجلات التي أنشأها الاختبار.
  • الحكم على تشغيل مقسّم إلى أجزاء بنتيجة جزء واحد بدلاً من التقرير المدمج لكل الأجزاء.
  • إعادة تشغيل حالات الفشل الناتجة عن التداخل حتى تنجح، مما يخفي الحالة المشتركة بدلاً من إزالتها.

من منظور ضمان الجودة

العزل شيء يستطيع المختبِر فحصه والمطالبة به. قبل أن تصبح الحزمة متوازية، وكلما راجعت اختباراً آلياً، طبّق أربعة فحوص: هل ينجح الاختبار وحده، وبترتيب عشوائي، ومرتين متتاليتين، ومع عدة عمّال؟ في Jest الخيار --randomize، والإضافة pytest-randomly تخلط ترتيب اختبارات pytest، وفي Playwright الخيار --repeat-each. ثم اسأل: ماذا يغيّر كل اختبار، ومن غيره يرى هذا التغيير؟ كثير من الإصلاحات يحتاج إلى المطورين أو فريق المنصة: واجهة برمجية لإنشاء حسابات اختبار، وطريقة لتفريغ السلة، ومستأجر (tenant) منفصل لكل تشغيل، وبيئة تتحمل حمل أربعة عمّال.

حين يفشل اختبار بالتوازي فقط، سجّل ما يميّز التداخل من عيب في المنتج: العامل والجزء اللذين عمل عليهما، والحساب ومعرّفات السجلات التي استخدمها، وما كان يعمل في الوقت نفسه، وهل ينجح وحده ومع عامل واحد. والتداخل المؤكَّد عيب في حزمة الاختبارات له مالك وإصلاح، لا ضجيج يُعاد تشغيله.

تمرين عملي

اجعل حزمة الإعدادات آمنة للتشغيل المتوازي

المطلوب

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

المادة
account-settings.spec.ts (Playwright)
Today:      workers: 1
Planned:    workers: 4, fullyParallel: true
Planned CI: --shard=1/2 and --shard=2/2, both against the same staging environment
Every test signs in as qa.settings@example.com

1  change name      sets the display name to "Sara A."
2  name in header   expects "Sara A." in the page header
3  enable 2FA       turns on two-factor sign-in for the account
4  export data      saves the export to downloads/export.zip, then opens it
5  default theme    sets the site-wide default theme to dark in the admin panel
6  language list    reads the list of supported languages and changes nothing
الخطوات
  1. لكل اختبار، اكتب ما يقرؤه وما يغيّره.
  2. علّم كل تغيير يقرؤه أو يغيّره اختبار آخر أيضاً.
  3. اختر إصلاحاً لكل منها: بيانات خاصة، أو ملف خاص، أو مورد لكل عامل، أو تشغيل تسلسلي منفصل.
  4. افحص ما يضيفه الجزآن، علماً بأن كليهما يستخدم بيئة staging نفسها.
إظهار الإجابة النموذجية
الإجابة النموذجية

الاختباران ⁦1⁩ و⁦2⁩: يعتمد الاختبار ⁦2⁩ على أن يكون الاختبار ⁦1⁩ قد عمل قبله على الحساب نفسه، ومع fullyParallel قد يعمل قبله أو على عامل آخر. الإصلاح: يحصل كل اختبار على حساب جديد من تجهيزة، ويضبط الاختبار ⁦2⁩ الاسم بنفسه عبر الواجهة البرمجية قبل أن يفحص رأس الصفحة.

الاختبار ⁦3⁩: تفعيل الدخول بخطوتين على الحساب المشترك يُفسد تسجيل الدخول لكل الاختبارات الأخرى، ومنها الاختبار ⁦6⁩ الذي يقرأ فقط. يحتاج إلى حساب جديد خاص به يمكنه حذفه بعد ذلك.

الاختبار ⁦4⁩: قد يكتب عاملان في downloads/export.zip في الوقت نفسه. احفظ في test.info().outputPath('export.zip') بدلاً من ذلك.

الاختبار ⁦5⁩: إعداد على مستوى الموقع لا يمكن عزله لكل حساب. انقله إلى تشغيل منفصل بالخيار --workers=1 يعمل مرة واحدة قبل مهام الأجزاء أو بعدها وليس في الوقت نفسه أبداً، لأنها جميعاً تستخدم بيئة staging نفسها. ويضبط هذا الاختبار السمة التي يتوقعها في بدايته ويعيد السمة الافتراضية في التنظيف. أما الاختبار ⁦6⁩ فيقرأ بيانات مرجعية مشتركة فقط، ويمكن أن يبقى كما هو متى سجّل الدخول بحساب خاص به أو بحساب للقراءة فقط.

الأجزاء: يستخدم الجزآن بيئة staging نفسها، لذا يجب أن تكون أسماء الحسابات فريدة عبر الأجزاء، بـUUID مثلاً، لأن رقم العامل وحده يتكرر. ادمج تقريري الجزأين في تقرير واحد قبل الحكم على التشغيل، وتأكد من الإصلاحات بعدة تشغيلات متكررة بأربعة عمّال.

أسئلة شائعة

هل يجعل التنفيذ المتوازي الاختبارات متذبذبة؟

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

ما الفرق بين العمّال والأجزاء؟

العمّال عمليات متوازية على جهاز واحد (وخيوط في JUnit 5)؛ والأجزاء أقسام من الحزمة تشغّلها أجهزة أو مهام CI منفصلة. ويمكن الجمع بينهما: أربعة أجزاء بأربعة عمّال لكل منها تشغّل حتى ستة عشر اختباراً في وقت واحد. يتشارك العمّال معالج الجهاز وقرصه، بينما لا تتشارك الأجزاء إلا بيئة الاختبار، ويجب دمج تقاريرها.

هل يجب أن يكون لكل اختبار حساب خاص؟

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

المراجع

  • Eradicating Non-Determinism in Tests (Martin Fowler)martinfowler.com · 2011لماذا تُفقد الاختبارات المتذبذبة الحزمةَ قيمتها، وأسبابها الشائعة (العزل وعدم التزامن والخدمات البعيدة والوقت وتسرّب الموارد)، والحجر كاستجابة.
  • Playwright DocumentationMicrosoft (Playwright)التوثيق الرسمي لـ Playwright، إطار الاختبار الشامل الذي يشغّل Chromium وWebKit وFirefox.
  • Best Practices — PlaywrightMicrosoft (Playwright)اختبر السلوك الذي يراه المستخدم، واجعل الاختبارات معزولة، وفضّل المحدِّدات المتينة والتأكيدات التي تنتظر، واستخدم التتبّع لتصحيح الأخطاء.
  • Best Practices — CypressCypress.ioإرشادات Cypress لاختيار العناصر بسمات مخصّصة، وتجنّب الانتظار الثابت، وإبقاء الاختبارات مستقلة.

تدرّب بأدوات متقن

توليد معرّفات UUID v4 (عشوائية) وv7 (مرتّبة زمنياً) بالجملة، والتحقق من المعرّفات الموجودة.

أدوات مساعدة

ولّد سجلات مستخدمين وهمية (الاسم واسم المستخدم والبريد الإلكتروني وكلمة المرور وبذرة الصورة الرمزية والدور) لحسابات الاختبار.

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

مصنع متكامل لبيانات الاختبار الاصطناعية: مستخدمون وعملاء وشركات وعناوين وأرقام وتواريخ وسلاسل نصية بصيغة JSON أو CSV أو SQL أو XML.

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

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة