الاختبار الآلي مع Pytest

تم إعداد ترجمة لهذه المقالة خصيصًا لطلاب دورة Python QA Engineer .




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

لماذا نحتاج الاختبارات الآلية


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

المتقدمة أداة اختبار pytest كامل المواصفات في بيثون


حاليا ، هناك العديد من الأطر والأدوات للاختبار. هناك أنواع مختلفة من الأطر ، على سبيل المثال ، القائمة على البيانات ، القائمة على الكلمات الرئيسية ، الهجينة ، BDD ، إلخ. يمكنك اختيار واحد يناسب احتياجاتك.

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

pytest إطار pytest من السهل كتابة اختبارات صغيرة ، لكنه أيضًا يدعم دعم الاختبارات الوظيفية المتطورة للتطبيقات والمكتبات.

بعض الميزات الرئيسية لل pytest :

  • الكشف التلقائي عن وحدات الاختبار والوظائف ؛
  • CLI فعال لتحسين التحكم في ما تريد تشغيله أو تخطيه ؛
  • نظام إيكولوجي كبير تابع لجهات خارجية ؛
  • تركيبات - أنواع مختلفة ، تطبيقات مختلفة ؛
  • العمل مع إطار اختبار الوحدة التقليدية.

اختبار الكشف التلقائي والقابل للتكوين


بشكل افتراضي ، تتوقع pytest العثور على اختبارات في وحدات Python التي تبدأ أسماؤها بـ test_ أو تنتهي بـ _test.py . أيضًا ، بشكل افتراضي ، تتوقع أن تبدأ أسماء وظائف الاختبار بالبادئة test_ . ومع ذلك ، يمكن تغيير بروتوكول الكشف عن الاختبار هذا عن طريق إضافة التكوين الخاص بك إلى أحد pytest تكوين pytest .

 # content of pytest.ini # Example 1: have pytest look for "check" instead of "test" # can also be defined in tox.ini or setup.cfg file, although the section # name in setup.cfg files should be "tool:pytest" [pytest] python_files = check_*.py python_classes = Check python_functions = *_check 

دعنا ننظر إلى وظيفة اختبار بسيطة للغاية:

 class CheckClass(object): def one_check(self): x = "this" assert 'h' in x def two_check(self): x = "hello" assert hasattr(x, 'check') 

هل لاحظت أي شيء؟ لا يوجد assertEqual أو assertDictEqual ، مجرد assert يمكن الوصول إليه ومفهوم. ليست هناك حاجة لاستيراد هذه الوظائف لمجرد مقارنة كائنين. التأكيد هو ما لدى بيثون بالفعل وليس هناك حاجة لإعادة اختراع العجلة.

رمز القالب؟ لا تقلق ، تركيبات التسرع في إنقاذ!


انظر إلى وظائف الاختبار التي تختبر العمليات الأساسية في برنامج Wallet:

 // test_wallet.py from wallet import Wallet def test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close() def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close() def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close() def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close() 

مهم ، مثيرة للاهتمام! هل لاحظت؟ هناك الكثير من التعليمات البرمجية. شيء آخر جدير بالملاحظة هو أن هذا الاختبار يقوم بشيء آخر إلى جانب اختبار الجزء الوظيفي ، على سبيل المثال ، إنشاء محفظة وإغلاقها باستخدام wallet.close() .

الآن دعونا نلقي نظرة على كيف يمكنك التخلص من شفرة الغليان باستخدام pytest pytest.

 import pytest from _pytest.fixtures import SubRequest from wallet import Wallet #==================== fixtures @pytest.fixture def wallet(request: SubRequest): param = getattr(request, 'param', None) if param: prepared_wallet = Wallet(initial_amount=param[0]) else: prepared_wallet = Wallet() yield prepared_wallet prepared_wallet.close() #==================== tests def test_default_initial_amount(wallet): assert wallet.balance == 0 @pytest.mark.parametrize('wallet', [(100,)], indirect=True) def test_setting_initial_amount(wallet): assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) def test_wallet_add_cash(wallet): wallet.add_cash(amount=90) assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(20,)], indirect=True) def test_wallet_spend_cash(wallet): wallet.spend_cash(amount=10) assert wallet.balance == 10 

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

 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) 

في بيئة أكثر تحكماً ، قد يكون لديك ملف به بيانات اختبار ، على سبيل المثال test-data.ini في test-data.ini أو shell الخاص بك ، والذي يمكنه قراءته ، في حين أن وظيفة الاختبار الخاصة بك يمكن أن تستدعي قذائف مختلفة لقراءة بيانات الاختبار.

ومع ذلك ، يوصى بوضع كل ما تبذلونه من التركيبات في ملف conftest.py خاص. هذا ملف خاص في pytest يسمح للاختبار باكتشاف التركيبات العالمية.

ولكن لدي حالات اختبار أريد تشغيلها على مجموعات بيانات مختلفة!


لا تقلق ، pytest لديه ميزة باردة لمعلمة المباراة الخاصة بك. لنلقِ نظرة على مثال.

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

قد تفكر في كتابة حالة اختبار منفصلة لكل من هذه المعلمات ، ولكن مع pytest كل شيء أبسط بكثير!

 @pytest.mark.parametrize(“setting_name, setting_value”, [('qdb_mem_usage', 'low'), ('report_crashes', 'yes'), ('stop_download_on_hang', 'no'), ('stop_download_on_disconnect', 'no'), ('reduce_connections_on_congestion', 'no'), ('global.max_web_users', '1024'), ('global.max_downloads', '5'), ('use_kernel_congestion_detection', 'no'), ('log_type', 'normal'), ('no_signature_check', 'no'), ('disable_xmlrpc', 'no'), ('disable_ntp', 'yes'), ('ssl_mode', 'tls_1_2'),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \'{0}\' is \'{1}\'.”.format(setting_name, setting_value), \ 'The {} default should be {}'.format(preference_name, preference_value) 

رائع ، أليس كذلك؟ لقد كتبت للتو 13 حالة اختبار (كل مجموعة تحدد setting_value مختلفًا) ، وفي المستقبل ، إذا أضفت معلمة جديدة إلى منتجك ، كل ما عليك فعله هو إضافة مجموعة أخرى.

كيف يتكامل pytest مع اختبار واجهة المستخدم مع اختبارات Selenium و API؟


حسنًا ، قد يحتوي منتجك على عدة واجهات. CLI - كما قلنا أعلاه. على غرار واجهة المستخدم الرسومية و API. قبل نشر منتج البرنامج ، من المهم اختبارها جميعًا. في برنامج المؤسسة ، حيث ترتبط عدة مكونات ببعضها وتعتمد على بعضها البعض ، يمكن أن يؤثر أي تغيير في جزء واحد على جميع المكونات الأخرى.

تذكر أن pytest هو مجرد إطار لسهولة الاختبار ، وليس نوعًا معينًا من الاختبارات. وهذا يعني أنه يمكنك إنشاء اختبارات واجهة المستخدم الرسومية باستخدام السيلينيوم أو ، على سبيل المثال ، اختبارات لواجهة برمجة التطبيقات مع مكتبة requests من بيثون وتشغيلها مع pytest .

على سبيل المثال ، على مستوى عالٍ ، قد يكون ذلك بمثابة فحص لبنية المستودع.



كما ترى في الصورة أعلاه ، فإنه يتيح فرصة جيدة لفصل المكونات:

apiobjects : مكان جيد لإنشاء غلافات لاستدعاء نقاط نهاية API. قد يكون لديك BaseAPIObject وفئة مشتقة تلبي الاحتياجات الخاصة بك.

المساعدون : يمكنك إضافة طرق المساعد الخاصة بك هنا.

lib : ملفات المكتبة التي يمكن استخدامها من قبل المكونات المختلفة ، على سبيل المثال ، conftest الخاصة بك في conftest ، pageobjects ، إلخ.

pageobjects : يمكن استخدام PageObjects بنية PageObjects لإنشاء فئات لصفحات واجهة المستخدم الرسومية المختلفة. نستخدم Webium ، وهي مكتبة لتطبيقات قوالب كائن الصفحة لبيثون.

suites : يمكنك كتابة مجموعات اختبار pylint الخاصة بك للحصول على الكود ، وسوف تساعدك على اكتساب المزيد من الثقة في جودة التعليمات البرمجية الخاصة بك

الاختبارات : يمكنك كتالوج الاختبارات بناءً على تفضيلاتك. هذا سيجعل من السهل إدارة ومراجعة الاختبارات الخاصة بك.

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

لدي العديد من حالات الاختبار وأريد منهم أن يعملوا بشكل متوازٍ


يمكن أن يكون لديك العديد من حالات الاختبار في مجموعتك ، ويحدث أنك تحتاج إلى تشغيلها بشكل متوازٍ وتقليل الوقت الإجمالي لتنفيذ الاختبار.

يقدم Pytest مكونًا إضافيًا رائعًا لتشغيل الاختبار الموازي يسمى pytest-xdist ، والذي يضيف عدة أوضاع فريدة للتنفيذ إلى pytest الأساسي. تثبيت هذا البرنامج المساعد باستخدام pip .

 pip install pytest-xdist 

دعونا نرى كيف يعمل مع مثال.

لدي مستودع للاختبار الآلي CloudApp لاختبارات واجهة المستخدم الرسومية الخاصة بـ Selenium. بالإضافة إلى ذلك ، فإنه ينمو باستمرار وتحديثها مع اختبارات جديدة والآن لديها المئات من الاختبارات. ما أريد القيام به هو تشغيلها بشكل متوازٍ وتقليل وقت تنفيذ الاختبار الكلي.

في الجهاز ، اكتب فقط pytest في مجلد / مجلد جذر المشروع. هذا سيسمح لك بإجراء جميع الاختبارات.

 pytest -s -v -n=2 



سوف pytest-xdist تشغيل جميع الاختبارات في وقت واحد!

بهذه الطريقة ، يمكنك أيضًا تشغيل مستعرضات متعددة بشكل متوازٍ.

تقارير


Pytest يأتي مع دعم مدمج لإنشاء ملفات نتائج الاختبار التي يمكن فتحها باستخدام Jenkins ، Bamboo ، أو خوادم التكامل المستمر الأخرى. استخدم ما يلي:

 pytest test/file/path — junitxml=path 

سيساعد هذا في إنشاء ملف XML كبير يمكن فتحه مع العديد من المحللون.

استنتاج


شعبية Pytest ينمو كل عام. بالإضافة إلى ذلك ، يحتوي على دعم مجتمعي قوي ، والذي يسمح لك بالوصول إلى العديد من الملحقات ، مثل pytest-django ، والتي سوف تساعدك على كتابة اختبارات لتطبيقات الويب في Django. تذكر أن pytest يدعم حالات اختبار unittest ، لذلك إذا كنت تستخدم unittest ، فيجب مراعاة pytest بمزيد من التفصيل.

مصادر



هذا كل شيء. أراك في الدورة !

Source: https://habr.com/ru/post/ar480186/


All Articles