الفرق بين المراجعتين لصفحة: «ReactNative/testing overview»
لا ملخص تعديل |
لا ملخص تعديل |
||
سطر 157: | سطر 157: | ||
==== اختبار الخرج المُصيَّر ==== | ==== اختبار الخرج المُصيَّر ==== | ||
[https://jestjs.io/docs/snapshot-testing اختبار اللقطات (Snapshot testing)] هو نوع متقدم من الاختبارات من Jest، وهو أداة قوية للغاية ومنخفضة المستوى، لذلك يُنصَح بالاهتمام بها عند استخدامها. | |||
"مكوّن اللقطة" هو عبارة عن سلسلة تشبه JSX أنشأها مسلسِل React مخصَّص ومدمج في Jest. يتيح هذا المسلسل لـ Jest بترجمة أشجار مكونات React إلى سلسلة يمكن للبشر قراءتها، أي مكوّن اللقطة هو تمثيل نصي لخرج مصيّر مكوّنك الذي أُنشِئ أثناء تشغيل الاختبار، ويبدو كما يلي:<syntaxhighlight lang="javascript"> | |||
<Text | |||
style={ | |||
Object { | |||
"fontSize": 20, | |||
"textAlign": "center", | |||
} | |||
}> | |||
Welcome to React Native! | |||
</Text> | |||
</syntaxhighlight>تنفّذ باستخدام اختبار اللقطة أولًا مكوّنك ثم تشغّل اختبار اللقطة، ثم ينشئ اختبار اللقطة لقطةً ويحفظها في ملف في الريبو الخاص بك كلقطة مرجعية، ثم يجب الالتزام بالملف ويجري التحقق منه أثناء مراجعة الشيفرة. ستؤدي أي تغييرات مستقبلية على خرج مصيّر المكون إلى تغيير لقطته، مما يؤدي إلى فشل الاختبار. تحتاج بعد ذلك إلى تحديث اللقطة المرجعية المخزَّنة حتى ينجح الاختبار، ويجب الالتزام بهذا التغيير ومراجعته مرة أخرى. | |||
تملك اللقطات نقاط ضعف متعددة وهي: | |||
* قد يكون معرفة ما إذا كان التغيير في اللقطة مقصودًا أم أنه دليل على وجود خطأ أمرًا صعبًا بالنسبة لك كمطوّر أو كمراجِع. يمكن أن يصبح من الصعب فهم اللقطات الكبيرة بشكل خاص وتصبح قيمتها المضافة منخفضة. | |||
* تُعَد اللقطة صحيحة عند إنشائها، حتى في الحالة التي يكون فيها الخرج المُصيَّر خاطئًا بالفعل. | |||
* يجب تحديث اللقطة عند فشلها باستخدام خيار jest الذي يُدعَى <code>updateSnapshot--</code> دون التحقق مما إذا كان التغيير متوقَّعًا أم لا، وبالتالي يجب على المطورين المحافظة على النظام. | |||
لا تضمن اللقطات نفسها صحة منطق تصيير مكوّنك، فهي فقط جيدة في الحماية من التغييرات غير المتوقعة وللتحقق من أن المكونات في شجرة React قيد الاختبار تتلقى الخصائص المتوقعة (الأشكال وغير ذلك). | |||
نوصي باستخدام لقطات صغيرة فقط (راجع [https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-large-snapshots.md قاعدة <code>no-large-snapshots</code>]). إن أردت اختبار تغيير بين حالتين من مكونات React، فاستخدم <code>[https://github.com/jest-community/snapshot-diff snapshot-diff]</code>. يفضَّل التوقعات التوقعات الصريحة كما هو موضح في الفقرة السابقة. | |||
[[ملف:p tests-snapshot.svg|بديل=tests snapshot|مركز|تصغير|425x425بك]] | |||
=== الاختبارات الشاملة End-to-End Tests === | |||
تتحقق في الاختبارات الشاملة (E2E) من أن تطبيقك يعمل كما هو متوقع على جهاز (أو جهاز محاكاة / محاكي) من وجهة نظر المستخدم. | |||
يمكن تنفيذ ذلك عن طريق بناء تطبيقك في إعداد الإصدار وتشغيل الاختبارات عليه. لن تفكر في اختبارات E2E بمكونات React أو واجهات برمجة تطبيقات React Native أو متاجر Redux أو أي منطق أعمال، إذ ليس هذا هو الغرض من اختبارات E2E والتي لا يمكن الوصول إليها حتى أثناء اختبار E2E. | |||
تسمح لك مكتبات اختبار E2E بدلًا من ذلك بالعثور على العناصر والتحكم فيها في شاشة تطبيقك، حيث يمكنك بالفعل النقر على الأزرار أو إدراج نص في <code>TextInputs</code> بنفس الطريقة التي يقوم بها المستخدم الحقيقي على سبيل المثال. يمكنك بعد ذلك إجراء تأكيدات حول ما إذا كان عنصر معين موجودًا في شاشة التطبيق أم لا، وما إذا كان مرئيًا أم لا، وما النص الذي يحتوي عليه، وما إلى ذلك. | |||
تمنحك اختبارات E2E أعلى ثقة ممكنة بأن جزءًا من تطبيقك يعمل، ولكن: | |||
* تستغرق كتابة هذه الاختبارات وقتًا أطول بالموازنة مع أنواع الاختبارات الأخرى. | |||
* وهي أبطأ في التشغيل. | |||
* وأكثر عرضة لعدم الاستقرار (الاختبار "غير المستقر flaky" هو اختبار ينجح ويفشل عشوائيًا دون أي تغيير في الشيفرة). | |||
حاول تغطية الأجزاء الحيوية من تطبيقك باختبارات E2E مثل تدفق الاستيثاق والوظائف الأساسية والمدفوعات وما إلى ذلك، واستخدم اختبارات JS الأسرع للأجزاء غير الحيوية من تطبيقك. كلما أضفت المزيد من الاختبارات، كلما زادت ثقتك بنفسك، ولكن زاد أيضًا الوقت الذي تقضيه في صيانتها وتشغيلها، لذلك أجرِ حساباتك وحدّد الأفضل لك. | |||
هناك العديد من أدوات اختبار E2E المتاحة، إذ يُعَد Detox إطار عمل شائعًا في مجتمع React Native لأنه مصمَّم لتطبيقات React Native. مكتبة أخرى شهيرة في فضاء تطبيقات iOS و Android هي [http://appium.io/ Appium]. | |||
[[ملف:p tests-e2e.svg|بديل=tests e2e|مركز|تصغير|392x392بك]] | |||
== الخلاصة == | |||
هناك العديد من الطرق التي يمكنك من خلالها اختبار تطبيقاتك. قد يكون من الصعب تحديد ما يجب استخدامه في البداية، ولكن نعتقد أن كل هذا سيكون منطقيًا بمجرد أن تبدأ في إضافة اختبارات إلى تطبيق React Native. | |||
== روابط مهمة == | |||
[[React/testing|نظرة عامة على اختبار مكونات React]] | |||
[https://callstack.github.io/react-native-testing-library/ مكتبة اختبار React Native] | |||
[https://jestjs.io/docs/tutorial-react-native توثيق Jest] | |||
[https://github.com/wix/detox/ Detox] | |||
[http://appium.io/ Appium] | |||
== مصادر == | |||
* [https://reactnative.dev/docs/testing-overview صفحة Testing في توثيق React Native الرسمي.] |
مراجعة 23:34، 3 يونيو 2021
الاختبار Testing
يمكن أن تتحول الأخطاء الصغيرة التي لا تتوقعها إلى حالات فشل أكبر مع توسع قاعدة الشيفرة، حيث تؤدي الأخطاء إلى تجربة مستخدم سيئة والتي ستؤدي في النهاية خسائر تجارية. تتمثل إحدى طرق منع البرمجة الضعيفة في اختبار شيفرتك قبل إصدارها.
سنغطّي طرقًا آلية مختلفة لضمان عمل تطبيقك كما هو متوقع بدءًا من التحليل الساكن إلى الاختبارات الشاملة.
أهمية عملية الاختبار
نحن بشر والبشر يخطئون. الاختبار مهم لأنه يساعدك في الكشف عن هذه الأخطاء والتحقق من عمل شيفرتك، ويضمن الاختبار استمرار عمل شيفرتك في المستقبل عند إضافة ميزات جديدة، أو إعادة بناء الميزات الموجودة، أو ترقية الاعتماديات الرئيسية لمشروعك.
من أفضل الطرق لإصلاح خطأ في شيفرتك هي كتابة اختبار فاشل يفضح هذا الخطأ، ثم إن نجح هذا الاختبار عند إصلاح الخطأ وإعادة تشغيله، فهذا يعني أن الخطأ قد أُصلِح، ولن يُعاد إدخاله في قاعدة الشيفرة مطلقًا.
يمكن أيضًا أن تكون الاختبارات بمثابة توثيق للأشخاص الجدد الذين ينضمون إلى فريقك، إذ يمكن أن تساعد اختبارات القراءة الأشخاص الذين لم يروا قاعدة بيانات من قبل على فهم كيفية عمل الشيفرة الموجودة.
وأخيرًا، يؤدي إجراء المزيد من الاختبارات الآلية إلى قضاء وقت أقل في عملية ضمان الجودة اليدوية، مما يوفر وقتًا ثمينًا.
التحليل الساكن Static Analysis
تتمثل الخطوة الأولى لتحسين جودة الشيفرة في البدء في استخدام أدوات التحليل الساكنة، إذ يفحص التحليل الساكن شيفرتك بحثًا عن الأخطاء أثناء كتابتها دون تشغيل أي من تلك الشيفرة.
- تحلّل أدوات Linter الشيفرة للكشف عن الأخطاء الشائعة مثل الشيفرة غير المستخدمة وللمساعدة في تجنب المخاطر، ولإعلام دليلٍ من النمط المحرَّم مثل استخدام مفايتح tab بدلًا من المسافات (أو العكس اعتمادًا على الإعداد الخاص بك).
- يضمن التحقق من النوع Type checking تطابق البنية التي تمرّرها إلى دالة ما صُمِّمت الدالة لقبوله، كمنع تمرير سلسلة إلى دالة حسابية تقبل أعدادًا.
يأتي إطار عمل React Native مع أداتين من هذا القبيل هما: ESLint للكشف عن الأخطاء و Flow للتحقق من النوع. يمكنك أيضًا استخدام لغة TypeScript، وهي لغة مكتوبة تُصرَّف إلى لغة JavaScript صِرفة.
كتابة شيفرة قابلة للاختبار
تحتاج لبدء الاختبارات أولًا إلى كتابة شيفرةٍ قابلة للاختبار. افترض مثلًا عملية تصنيع الطائرات، حيث يجري اختبار أجزاء الطائرة لضمان أنها آمنة وتعمل بصورةٍ صحيحة قبل إقلاع الطائرة لأول مرة لإثبات أن جميع أنظمتها المعقدة تعمل مع بعضها البعض بصورة جيدة، إذ تُختبَر الأجنحة عن طريق ثنيها تحت حمولة شديدة، وتُختبَر أجزاء المحرك للتأكد من متانتها، ويُختبَر الزجاج الأمامي ضد تأثير محاكاة الطيور.
البرمجيات مشابهة للطائرة، إذ يمكنك كتابة شيفرتك ضمن وحدات صغيرة متعددة بدلًا من كتابة برنامجك بالكامل في ملف ضخم واحد يحتوي على العديد من الأسطر البرمجية، بحيث يمكنك اختبار وحدات الشيفرة اختبارًا أكثر شمولًا من اختبار جميع الشيفرة. تتشابك بهذه الطريقة كتابة الشيفرة القابلة للاختبار مع كتابة شيفرة معيارية دون اخطاء.
يمكنك جعل تطبيقك أكثر قابلية للاختبار من خلال فصل جزء عرض تطبيقك (أو مكونات React) عن منطق عملك وحالة التطبيق (بغض النظر عما إذا استخدمت Redux أو MobX أو حلولًا أخرى). يمكنك باستخدام هذه الطريقة الاحتفاظ باختبار منطق عملك (والذي لا ينبغي أن يعتمد على مكونات React) بصورةٍ مستقلة عن المكونات نفسها، فالهدف الأساسي هو إخراج واجهة مستخدم تطبيقك.
يمكنك الذهاب إلى أبعد من ذلك نظريًا من خلال نقل كل المنطق والبيانات المجلوبة من مكوناتك، وبالتالي ستُخصَّص مكوناتك فقط للإخراج، وستكون حالتك مستقلة تمامًا عن مكوناتك، إذ سيعمل منطق تطبيقك بدون أي مكونات React على الإطلاق.
اختبارات الكتابة
يجب الآن كتابة بعض الاختبارات الفعلية بعد كتابة شيفرة قابلة للاختبار. يُحمَّل قالب React Native الافتراضي مع إطار عمل اختبار Jest، ويشتمل هذا القالب على إعداد مسبق مصمَّم خصيصًا لهذه البيئة حتى تتمكن من زيادة الإنتاجية دون تعديل الإعداد والتزييفات mocks (سنتكلم لاحقًا عن التزييف mocking). يمكنك استخدام Jest لكتابة جميع أنواع الاختبارات.
إن أجريت تطويرًا يعتمد على الاختبار، فيجب كتابة الاختبارات أولًا، وبالتالي تصبح شيفرتك قابلة للاختبار.
بنية الاختبارات
يجب أن تكون اختباراتك قصيرة وتختبر شيئًا واحدًا فقط. لنبدأ بمثال اختبار وحدة مكتوب باستخدام Jest:
it('given a date in the past, colorForDueDate() returns red', () => {
expect(colorForDueDate('2000-10-20')).toBe('red');
});
يوصَف الاختبار بواسطة السلسلة المُمرَّرة إلى الدالة it
. احرص على كتابة الوصف مع توضيح ما تختبره، إذ يجب أن يتضمن الوصف ما يلي:
- Given: بعض الشروط المسبقة
- When: بعض الإجراءات التي تنفّذها الدالة التي تختبرها
- Then: النتيجة المتوقعة
يُعرف ذلك أيضًا باسم AAA (Arrange, Act, Assert).
يقدّم Jest دالة describe
للمساعدة في تنظيم اختباراتك. استخدم دالة describe
لتجميع جميع الاختبارات التي تنفّذ المهمة نفسها، ويمكن أن تتداخل الأوصاف، إذا كنت بحاجة إلى ذلك. الدوال الأخرى التي ستستخدمها هي beforeEach
أو beforeAll
التي يمكنك استخدامها لإعداد الكائنات التي تختبرها. اقرأ المزيد في Jest api reference.
إذا كان الاختبار الخاص بك يحتوي على العديد من الخطوات أو التوقعات، فقد تقسّمه إلى عدة خطوات أصغر. تأكد أيضًا من أن اختباراتك مستقلة تمامًا عن بعضها البعض، إذ يجب أن يكون كل اختبار في مجموعتك قابلًا للتنفيذ بمفرده دون إجراء اختبار آخر أولًا. بينما إذا أجريت جميع اختباراتك معًا، فيجب ألا يؤثر الاختبار الأول على خرج الاختبار الثاني.
أخيرًا، يحب المطورون عندما تعمل شيفرتهم دون أخطاء، والعكس صحيح عند تطبيق الاختبارات، فالاختبار الفاشل هو شيء جيد. يخبرنا فشل الاختبار أن هناك شيئًا ما ليس صحيحًا، وهذا يمنحك فرصة لإصلاح المشكلة قبل أن تؤثر على المستخدمين.
اختبارات الوحدة Unit tests
تغطي اختبارات الوحدة أصغر أجزاء الشيفرة، مثل الدوال أو الأصناف الفردية.
إذا احتوى الكائن قيد الاختبار على أي اعتماديات، فيجب تزييفه كما هو موضح في الفقرة التالية.
ميزة اختبارات الوحدة هي أنها سريعة في الكتابة والتشغيل، لذلك تحصل أثناء عملك على ملاحظات سريعة حول نجاح اختباراتك أو فشلها. يمتلك Jest أيضًا خيارًا لتشغيل الاختبارات ذات الصلة بالشيفرة الذي تعدلها، وهذا الخيار هو Watch mode.
التزييف Mocking
قد ترغب أحيانًا في تزييف الكائنات المُختبَرة عندما تحتوي على اعتماديات خارجية. "التزييف" هو استبدال جزء من اعتمادية شيفرتك بالتنفيذ الخاص بك.
يُعَد استخدام أشياء حقيقية في اختباراتك أفضل من استخدام التزييفات ولكن هناك مواقف لا يكون فيها ذلك ممكنًا، كالحالة التي يعتمد فيها اختبار وحدة JS على وحدة أصيلة مكتوبة بلغة Java أو Objective-C.
تخيل أنك تكتب تطبيقًا يعرض الطقس الحالي في مدينتك وأنك تستخدم خدمة خارجية أو اعتمادية أخرى تزودك بمعلومات الطقس. إن أخبرتك الخدمة أن السماء تمطر، فستعرض صورة بها سحابة ممطرة. لا يجب استدعاء هذه الخدمة في اختباراتك للأسباب التالية:
- يمكن أن تبطّئ الاختبارات وتجعلها وغير مستقرة (بسبب طلبات الشبكة المشوَّشة)
- قد تعيد الخدمة بيانات مختلفة في كل مرة تشغّل فيها الاختبار
- يمكن أن تصبح الخدمات الخارجية في وضع عدم الاتصال عندما تحتاج إلى إجراء الاختبارات
لذلك يمكنك توفير تنفيذ خدمة مزيف، واستبدال آلاف سطور الشيفرة وبعض الأجهزة المتصلة بالإنترنت بفعالية
يأتي Jest مع دعم للتزييف من تزييف مستوى الدالة وصولًا إلى تزييف مستوى الوحدة.
اختبارات التكامل Integration Tests
يجب أن تتفاعل الأجزاء الفردية مع بعضها البعض عند كتابة أنظمة برمجية أكبر. إذا اعتمدت وحدتك على وحدة أخرى في اختبار الوحدة، فسينتهي بك الأمر في بعض الأحيان إلى تزييف الاعتمادية، واستبدالها باعتمادية أخرى مزيفة.
، تُدمَج الوحدات الفردية الحقيقية (كما هو الحال في تطبيقك) وتُختَبر معًا في اختبار التكامل للتأكد من أنها تتعاون كما هو متوقع. هذا لا يعني أن التزييف لا يحدث هنا، إذ ستظل بحاجة إلى التزييف (مثل تزييف التواصل مع خدمة الطقس)، ولكنك ستحتاج إليه أقل بكثير من اختبار الوحدة.
لاحظ أن المصطلحات المتعلقة بما يعنيه اختبار التكامل ليست متناسقة دائمًا، وقد لا يكون الخط الفاصل بين اختبار الوحدة اختبار التكامل واضحًا دائمًا. يندرج اختبارك تحت النوع "اختبار التكامل" إذا كان:
- يجمع بين عدة وحدات من تطبيقك كما هو موضح أعلاه
- يستخدم نظام خارجي
- يستدعي تطبيقًا آخر عبر الشبكة (مثل واجهة برمجة تطبيقات خدمة الطقس)
- يجري أي نوع من أنواع إدخال وإخراج الملفات أو قواعد البيانات
اختبار المكونات Component Tests
مكونات React هي المسؤولة عن إخراج تطبيقك، وسيتفاعل المستخدمون مباشرةً مع مخرجاتهم. حتى إن احتوى منطق عمل تطبيقك على تغطية اختبار عالية وكان صحيحًا، لا يزال بإمكانك تقديم واجهة مستخدم معطلة للمستخدمين بدون اختبار المكونات. يمكن أن تندرج اختبارات المكونات في كل من اختبار الوحدة واختبار التكامل، ولكن سنشرحها بصورة منفصلة لأنها جزء أساسي من React Native.
هناك شيئان قد ترغب في اختبارهما لاختبار مكونات React هما:
- التفاعل Interaction: للتأكد من أن المكون يتصرّف تصرّفًا صحيحًا عند تفاعله مع المستخدم (عندما يضغط المستخدم على زر مثلًا).
- الإخراج Rendering: للتأكد من صحة إخراج المكون الذي تستخدمه React (كمظهر الزر وموضعه في واجهة المستخدم).
إذا كان لديك زر له متنصّت onPress
، فيجب اختبار أن الزر يظهر بصورة صحيحة وأن النقر على الزر يعالجه المكون معالجةً صحيحة.
هناك العديد من المكتبات التي يمكن أن تساعدك في إجراء هذين الاختبارَين:
- يوفّر مصيّر الاختبار Test Renderer الخاص بمكتبة React، الذي طُوِّر جنبًا إلى جنب مع صميمه، مصيّر React الذي يمكن استخدامه لتصيير مكونات React إلى كائنات JavaScript نقية، دون الاعتماد على DOM أو بيئة الجوّال الأصيلة.
- تُبنَى مكتبة React Native Testing Library على مصيّر اختبار React وتضيف
fireEvent
وquery
الخاص بواجهات برمجة التطبيقات الموضَّحة في الفقرة التالية.
اختبارات المكونات هي فقط اختبارات JavaScript مُشغَّلة في بيئة Node.js. لا تأخذ هذه الاختبارات في الحسبان أي شيفرة لنظام iOS أو Android أو لأي منصة أخرى تدعم مكونات React Native، وبالتالي لا يمكن أن تمنحك هذه الاختبارات ثقة بنسبة 100% في أن كل شيء يعمل لدى المستخدم. إذا كان هناك خطأ في شيفرة iOS أو Android، فلن تعثر هذه الاختبارات عليه.
اختبار تفاعلات المستخدم
تتعامل مكوناتك -بغض النظر عن تصيير واجهة المستخدم- مع أحداث مثل onChangeText
للمكون TextInput
أو onPress
للمكوّن Button
، وقد تحتوي مكوناتك أيضًا على دوال أخرى وعمليات استدعاء للأحداث. افترض المثال التالي:
function GroceryShoppingList() {
const [groceryItem, setGroceryItem] = useState('');
const [items, setItems] = useState([]);
const addNewItemToShoppingList = useCallback(() => {
setItems([groceryItem, ...items]);
setGroceryItem('');
}, [groceryItem, items]);
return (
<>
<TextInput
value={groceryItem}
placeholder="Enter grocery item"
onChangeText={(text) => setGroceryItem(text)}
/>
<Button
title="Add the item to list"
onPress={addNewItemToShoppingList}
/>
{items.map((item) => (
<Text key={item}>{item}</Text>
))}
</>
);
}
اختبر المكون من منظور المستخدم عند اختبار تفاعلات المستخدم مثل اختبار ماذا يوجد في الصفحة؟ وما الذي يتغير عند التفاعل معها؟
يُفضَّل كقاعدة عامة استخدام الأشياء التي يمكن للمستخدمين رؤيتها أو سماعها مثل:
- عمل تأكيدات باستخدام النص المُصيَّر أو مساعدي إمكانية الوصول accessibility helpers
لكن يجب تجنّب ما يلي:
- إنشاء تأكيدات على خصائص props المكون أو حالته state
- استعلامات testID
تجنّب اختبار تفاصيل التنفيذ مثل الخصائص أو الحالة أثناء عمل هذه الاختبارات، فإنها ليست موجَّهة إلى كيفية تفاعل المستخدمين مع المكوّن وتميل إلى الانقطاع عن طريق إعادة البناء (عندما ترغب في إعادة تسمية بعض الأشياء أو إعادة كتابة مكون الصنف باستخدام الخطافات على سبيل المثال).
تميل مكونات صنف React إلى اختبار تفاصيل التنفيذ الخاصة بها مثل الحالة الداخلية أو الخصائص أو معالجات الأحداث. يفضَّل استخدام مكونات الدالة مع الخطافات لتجنب اختبار تفاصيل التنفيذ، مما يجعل الاعتماد على المكونات الداخلية أصعب.
تسهّل مكتبات اختبار المكونات مثل React Native Testing Library كتابة الاختبارات التي تركّز على المستخدم من خلال الاختيار الدقيق لواجهات برمجة التطبيقات المتوفرة. يستخدم المثال التالي توابع fireEvent
و changeText
و press
التي تحاكي مستخدمًا يتفاعل مع المكوّن ودالة استعلام getAllByText
التي تعثر على العقد Text
المتطابقة في الخرج المُصيَّر.
test('given empty GroceryShoppingList, user can add an item to it', () => {
const { getByPlaceholder, getByText, getAllByText } = render(
<GroceryShoppingList />
);
fireEvent.changeText(
getByPlaceholder('Enter grocery item'),
'banana'
);
fireEvent.press(getByText('Add the item to list'));
const bananaElements = getAllByText('banana');
expect(bananaElements).toHaveLength(1); // expect 'banana' to be on the list
});
لا يختبر هذا المثال كيفية تغيّر بعض الحالات عند استدعاء دالة، ولكنه يختبر ما يحدث عندما يغير المستخدم النص في TextInput
وعندما يضغط على الزر Button
.
اختبار الخرج المُصيَّر
اختبار اللقطات (Snapshot testing) هو نوع متقدم من الاختبارات من Jest، وهو أداة قوية للغاية ومنخفضة المستوى، لذلك يُنصَح بالاهتمام بها عند استخدامها.
"مكوّن اللقطة" هو عبارة عن سلسلة تشبه JSX أنشأها مسلسِل React مخصَّص ومدمج في Jest. يتيح هذا المسلسل لـ Jest بترجمة أشجار مكونات React إلى سلسلة يمكن للبشر قراءتها، أي مكوّن اللقطة هو تمثيل نصي لخرج مصيّر مكوّنك الذي أُنشِئ أثناء تشغيل الاختبار، ويبدو كما يلي:
<Text
style={
Object {
"fontSize": 20,
"textAlign": "center",
}
}>
Welcome to React Native!
</Text>
تنفّذ باستخدام اختبار اللقطة أولًا مكوّنك ثم تشغّل اختبار اللقطة، ثم ينشئ اختبار اللقطة لقطةً ويحفظها في ملف في الريبو الخاص بك كلقطة مرجعية، ثم يجب الالتزام بالملف ويجري التحقق منه أثناء مراجعة الشيفرة. ستؤدي أي تغييرات مستقبلية على خرج مصيّر المكون إلى تغيير لقطته، مما يؤدي إلى فشل الاختبار. تحتاج بعد ذلك إلى تحديث اللقطة المرجعية المخزَّنة حتى ينجح الاختبار، ويجب الالتزام بهذا التغيير ومراجعته مرة أخرى.
تملك اللقطات نقاط ضعف متعددة وهي:
- قد يكون معرفة ما إذا كان التغيير في اللقطة مقصودًا أم أنه دليل على وجود خطأ أمرًا صعبًا بالنسبة لك كمطوّر أو كمراجِع. يمكن أن يصبح من الصعب فهم اللقطات الكبيرة بشكل خاص وتصبح قيمتها المضافة منخفضة.
- تُعَد اللقطة صحيحة عند إنشائها، حتى في الحالة التي يكون فيها الخرج المُصيَّر خاطئًا بالفعل.
- يجب تحديث اللقطة عند فشلها باستخدام خيار jest الذي يُدعَى
updateSnapshot--
دون التحقق مما إذا كان التغيير متوقَّعًا أم لا، وبالتالي يجب على المطورين المحافظة على النظام.
لا تضمن اللقطات نفسها صحة منطق تصيير مكوّنك، فهي فقط جيدة في الحماية من التغييرات غير المتوقعة وللتحقق من أن المكونات في شجرة React قيد الاختبار تتلقى الخصائص المتوقعة (الأشكال وغير ذلك).
نوصي باستخدام لقطات صغيرة فقط (راجع قاعدة no-large-snapshots
). إن أردت اختبار تغيير بين حالتين من مكونات React، فاستخدم snapshot-diff
. يفضَّل التوقعات التوقعات الصريحة كما هو موضح في الفقرة السابقة.
الاختبارات الشاملة End-to-End Tests
تتحقق في الاختبارات الشاملة (E2E) من أن تطبيقك يعمل كما هو متوقع على جهاز (أو جهاز محاكاة / محاكي) من وجهة نظر المستخدم.
يمكن تنفيذ ذلك عن طريق بناء تطبيقك في إعداد الإصدار وتشغيل الاختبارات عليه. لن تفكر في اختبارات E2E بمكونات React أو واجهات برمجة تطبيقات React Native أو متاجر Redux أو أي منطق أعمال، إذ ليس هذا هو الغرض من اختبارات E2E والتي لا يمكن الوصول إليها حتى أثناء اختبار E2E.
تسمح لك مكتبات اختبار E2E بدلًا من ذلك بالعثور على العناصر والتحكم فيها في شاشة تطبيقك، حيث يمكنك بالفعل النقر على الأزرار أو إدراج نص في TextInputs
بنفس الطريقة التي يقوم بها المستخدم الحقيقي على سبيل المثال. يمكنك بعد ذلك إجراء تأكيدات حول ما إذا كان عنصر معين موجودًا في شاشة التطبيق أم لا، وما إذا كان مرئيًا أم لا، وما النص الذي يحتوي عليه، وما إلى ذلك.
تمنحك اختبارات E2E أعلى ثقة ممكنة بأن جزءًا من تطبيقك يعمل، ولكن:
- تستغرق كتابة هذه الاختبارات وقتًا أطول بالموازنة مع أنواع الاختبارات الأخرى.
- وهي أبطأ في التشغيل.
- وأكثر عرضة لعدم الاستقرار (الاختبار "غير المستقر flaky" هو اختبار ينجح ويفشل عشوائيًا دون أي تغيير في الشيفرة).
حاول تغطية الأجزاء الحيوية من تطبيقك باختبارات E2E مثل تدفق الاستيثاق والوظائف الأساسية والمدفوعات وما إلى ذلك، واستخدم اختبارات JS الأسرع للأجزاء غير الحيوية من تطبيقك. كلما أضفت المزيد من الاختبارات، كلما زادت ثقتك بنفسك، ولكن زاد أيضًا الوقت الذي تقضيه في صيانتها وتشغيلها، لذلك أجرِ حساباتك وحدّد الأفضل لك.
هناك العديد من أدوات اختبار E2E المتاحة، إذ يُعَد Detox إطار عمل شائعًا في مجتمع React Native لأنه مصمَّم لتطبيقات React Native. مكتبة أخرى شهيرة في فضاء تطبيقات iOS و Android هي Appium.
الخلاصة
هناك العديد من الطرق التي يمكنك من خلالها اختبار تطبيقاتك. قد يكون من الصعب تحديد ما يجب استخدامه في البداية، ولكن نعتقد أن كل هذا سيكون منطقيًا بمجرد أن تبدأ في إضافة اختبارات إلى تطبيق React Native.
روابط مهمة
نظرة عامة على اختبار مكونات React