ما هو اختبار BDD؟ مثال الإطار
ما هو اختبار BDD (التطوير الموجه بالسلوك)؟
اختبار BDD (التطوير المبني على السلوك). هي تقنية لتطوير البرمجيات الرشيقة وهي بمثابة امتداد لـ TDD، أي التطوير المبني على الاختبار. في BDD، تتم كتابة حالات الاختبار بلغة طبيعية يمكن حتى لغير المبرمجين قراءتها.
كيف يعمل اختبار BDD؟
ضع في اعتبارك أنه تم تكليفك بإنشاء وحدة تحويل الأموال في تطبيق Net Banking.
هناك طرق متعددة لاختباره
- يجب أن يتم تحويل الأموال إذا كان هناك رصيد كافٍ في الحساب المصدر
- يجب أن يتم تحويل الأموال إذا كانت تفاصيل الحساب الوجهة صحيحة
- يجب أن يتم تحويل الأموال إذا كانت كلمة مرور المعاملة / رمز RSA / مصادقة الأمان للمعاملة التي أدخلها المستخدم صحيحة
- يجب أن يتم تحويل الأموال حتى لو كانت عطلة البنوك
- يجب أن يتم تحويل الأموال في تاريخ مستقبلي يحدده صاحب الحساب
استخدم سيناريو الاختبار تصبح أكثر تفصيلاً وتعقيدًا عندما نأخذ في الاعتبار ميزات إضافية مثل مبلغ التحويل X لفترة زمنية Y أيام/أشهر، وإيقاف التحويل المجدول عندما يصل المبلغ الإجمالي إلى Z، وما إلى ذلك
الاتجاه العام للمطورين هو تطوير الميزات وكتابة كود الاختبار لاحقًا. كما هو واضح في الحالة أعلاه، حالة الاختبار إن التطوير لهذه الحالة معقد وسيقوم المطور بتأجيله الاختبار حتى إطلاق سراحه، وعند هذه النقطة سيجري اختبارًا سريعًا ولكن غير فعال.
للتغلب على هذه المشكلة (التنمية المدفوعة بالسلوك)، تم تصميم BDD. فهو يجعل عملية الاختبار بأكملها سهلة للمطور
في BDD، كل ما تكتبه يجب أن يدخل فيه نظرا-متى-ثم خطوات. لنفكر في نفس المثال أعلاه في BDD
Given that a fund transfer module in net banking application has been developed And I am accessing it with proper authentication
WhenI shall transfer with enough balance in my source account Or I shall transfer on a Bank Holiday Or I shall transfer on a future date And destination a/c details are correct And transaction password/rsa code / security authentication for the transaction is correct And press or click send button
Then amount must be transferred And the event will be logged in log file
أليس من السهل الكتابة والقراءة والفهم؟ وهو يغطي جميع حالات الاختبار المحتملة لوحدة تحويل الأموال ويمكن تعديله بسهولة لاستيعاب المزيد. كما أنها أشبه بكتابة الوثائق الخاصة بوحدة تحويل الأموال.
ما هو اختبار REST API؟
نظرًا لأن REST أصبح أسلوبًا شائعًا جدًا لبناء واجهات برمجة التطبيقات في الوقت الحاضر، فقد أصبح من المهم أيضًا أتمتة حالات اختبار REST API جنبًا إلى جنب مع حالات اختبار واجهة المستخدم. لذلك في الأساس، هذه الراحة اختبار API يتضمن اختبار إجراءات CRUD (إنشاء - قراءة - تحديث - حذف) باستخدام طرق POST وGET وPUT وDELETE على التوالي.
ما هو التصرف؟
التصرف هو واحد من شعبية Python أطر اختبار BDD.
دعونا نرى كيف يعمل التصرف:
تتم كتابة ملفات الميزات بواسطة محلل أعمالك / الراعي / أي شخص يتضمن سيناريوهات سلوكك. يحتوي على تنسيق لغة طبيعية يصف ميزة أو جزء من الميزة مع أمثلة تمثيلية للنتائج المتوقعة
يتم تعيين خطوات السيناريو هذه مع تطبيقات الخطوات المكتوبة Python.
واختياريًا، هناك بعض الضوابط البيئية (رمز للتشغيل قبل وبعد الخطوات أو السيناريوهات أو الميزات أو مباراة التصوير بأكملها).
لنبدأ بإعداد إطار اختبار الأتمتة الخاص بنا باستخدام Behave:
إعداد إطار عمل اختبار BDD Windows
تركيب:
- Python 3 من https://www.python.org/
- قم بتنفيذ الأمر التالي في موجه الأوامر لتثبيت Bespoke
- تثبيت النقطة تتصرف
- IDE: لقد استخدمت PyCharm Community Edition https://www.jetbrains.com/pycharm/download
إعداد مشروع:
- إنشاء مشروع جديد
- إنشاء هيكل الدليل التالي:
ملفات الميزة:
لذلك دعونا نبني ملف الميزات الخاص بنا Sample_REST_API_Testing.feature يحتوي على ميزة إجراء عمليات CRUD على خدمة "المشاركات".
في مثالنا، لقد استخدمت http://jsonplaceholder.typicode.com/ المشاركات عينة خدمة REST.
مثال على سيناريو ما بعد
Scenario: POST post example ->Here we are considering creating new post item using 'posts' service Given: I set post posts API endpoint ->This is prerequisite for the test which is setting URL of posts service When: I set HEADER param request content type as "application/json." And set request body And send POST HTTP request ->This is actual test step of sending a post request Then: Then I receive valid HTPP response code 201 And Response body "POST" is non-empty-> This is verification of response body
وبالمثل، يمكنك كتابة السيناريوهات المتبقية على النحو التالي:
Sample_REST_API_Testing.feature
Feature: Test CRUD methods in Sample REST API testing framework
Background:
Given I set sample REST API url
Scenario: POST post example
Given I Set POST posts api endpoint
When I Set HEADER param request content type as "application/json."
And Set request Body
And Send a POST HTTP request
Then I receive valid HTTP response code 201
And Response BODY "POST" is non-empty.
Scenario: GET posts example
Given I Set GET posts api endpoint "1"
When I Set HEADER param request content type as "application/json."
And Send GET HTTP request
Then I receive valid HTTP response code 200 for "GET."
And Response BODY "GET" is non-empty
Scenario: UPDATE posts example
Given I Set PUT posts api endpoint for "1"
When I Set Update request Body
And Send PUT HTTP request
Then I receive valid HTTP response code 200 for "PUT."
And Response BODY "PUT" is non-empty
Scenario: DELETE posts example
Given I Set DELETE posts api endpoint for "1"
When I Send DELETE HTTP request
Then I receive valid HTTP response code 200 for "DELETE."
خطوات التنفيذ
الآن، بالنسبة لخطوات الميزة المستخدمة في السيناريوهات المذكورة أعلاه، يمكنك كتابة عمليات التنفيذ فيها Python الملفات في دليل "الخطوات".
يحدد إطار العمل وظيفة الخطوة من خلال المزخرفات المتطابقة مع مسند ملف الميزة. على سبيل المثال، المسند المحدد في سيناريو ملف الميزة يبحث عن وظيفة الخطوة التي تحتوي على "معطى" للديكور. تحدث مطابقة مماثلة لـ متى وبعد ذلك. ولكن في حالة "لكن" و"و"، تأخذ وظيفة الخطوة الديكور بنفس الطريقة التي كانت بها الخطوة السابقة. على سبيل المثال، إذا جاء "و" بدلاً من "معطى"، فإن أداة تزيين دالة الخطوة المطابقة هي @given.
على سبيل المثال، عندما يمكن تنفيذ خطوة POST على النحو التالي:
@when (u'I Set HEADER param request content type as "{header_conent_type}"')
Mapping of When, here notice “application/json” is been passed from feature file for "{header_conent_type}” . This is called as parameterization
def step_impl (context, header_conent_type):
This is step implementation method signature
request_headers['Content-Type'] = header_conent_type
Step implementation code, here you will be setting content type for request header
وبالمثل، فإن تنفيذ الخطوات الأخرى في ملف step python سيبدو كما يلي:
Sample_step_implementation.py
from behave import given, when, then, step
import requests
api_endpoints = {}
request_headers = {}
response_codes ={}
response_texts={}
request_bodies = {}
api_url=None
@given(u'I set sample REST API url')
def step_impl(context):
global api_url
api_url = 'http://jsonplaceholder.typicode.com'
# START POST Scenario
@given(u'I Set POST posts api endpoint')
def step_impl(context):
api_endpoints['POST_URL'] = api_url+'/posts'
print('url :'+api_endpoints['POST_URL'])
@when(u'I Set HEADER param request content type as "{header_conent_type}"')
def step_impl(context, header_conent_type):
request_headers['Content-Type'] = header_conent_type
#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Set request Body')
def step_impl(context):
request_bodies['POST']={"title": "foo","body": "bar","userId": "1"}
#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send POST HTTP request')
def step_impl(context):
# sending get request and saving response as response object
response = requests.post(url=api_endpoints['POST_URL'], json=request_bodies['POST'], headers=request_headers)
#response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
# extracting response text
response_texts['POST']=response.text
print("post response :"+response.text)
# extracting response status_code
statuscode = response.status_code
response_codes['POST'] = statuscode
@then(u'I receive valid HTTP response code 201')
def step_impl(context):
print('Post rep code ;'+str(response_codes['POST']))
assert response_codes['POST'] is 201
# END POST Scenario
# START GET Scenario
@given(u'I Set GET posts api endpoint "{id}"')
def step_impl(context,id):
api_endpoints['GET_URL'] = api_url+'/posts/'+id
print('url :'+api_endpoints['GET_URL'])
#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send GET HTTP request')
def step_impl(context):
# sending get request and saving response as response object
response = requests.get(url=api_endpoints['GET_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
# extracting response text
response_texts['GET']=response.text
# extracting response status_code
statuscode = response.status_code
response_codes['GET'] = statuscode
@then(u'I receive valid HTTP response code 200 for "{request_name}"')
def step_impl(context,request_name):
print('Get rep code for '+request_name+':'+ str(response_codes[request_name]))
assert response_codes[request_name] is 200
@then(u'Response BODY "{request_name}" is non-empty')
def step_impl(context,request_name):
print('request_name: '+request_name)
print(response_texts)
assert response_texts[request_name] is not None
# END GET Scenario
#START PUT/UPDATE
@given(u'I Set PUT posts api endpoint for "{id}"')
def step_impl(context,id):
api_endpoints['PUT_URL'] = api_url + '/posts/'+id
print('url :' + api_endpoints['PUT_URL'])
@when(u'I Set Update request Body')
def step_impl(context):
request_bodies['PUT']={"title": "foo","body": "bar","userId": "1","id": "1"}
@when(u'Send PUT HTTP request')
def step_impl(context):
# sending get request and saving response as response object # response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
response = requests.put(url=api_endpoints['PUT_URL'], json=request_bodies['PUT'], headers=request_headers)
# extracting response text
response_texts['PUT'] = response.text
print("update response :" + response.text)
# extracting response status_code
statuscode = response.status_code
response_codes['PUT'] = statuscode
#END PUT/UPDATE
#START DELETE
@given(u'I Set DELETE posts api endpoint for "{id}"')
def step_impl(context,id):
api_endpoints['DELETE_URL'] = api_url + '/posts/'+id
print('url :' + api_endpoints['DELETE_URL'])
@when(u'I Send DELETE HTTP request')
def step_impl(context):
# sending get request and saving response as response object
response = requests.delete(url=api_endpoints['DELETE_URL'])
# response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
# extracting response text
response_texts['DELETE'] = response.text
print("DELETE response :" + response.text)
# extracting response status_code
statuscode = response.status_code
response_codes['DELETE'] = statuscode
#END DELETE
تشغيل الاختبارات
لقد انتهينا الآن من جزء تطوير البرنامج النصي للاختبار، لذا فلنجري اختباراتنا:
قم بتنفيذ الأمر التالي على موجه الأوامر لتشغيل ملف الميزة الخاص بنا
ج: \البرامج\Python\Python37>تتصرف جميلة ج:\ \الميزات\feature_files_folder\Sample_REST_API_Testing.feature
سيعرض هذا نتائج تنفيذ الاختبار كما يلي:
عرض التقرير على وحدة التحكم
دعونا نرى شيئًا رائعًا آخر هنا.
نظرًا لأن المستخدمين يفضلون دائمًا رؤية نتائج الاختبار بتنسيق أكثر قابلية للقراءة والعرض، فلنقم بإعداد التقارير بتنسيق HTML بمساعدة Allure.
التقارير
أولاً، تحتاج إلى تثبيت مُنسق Allure Behave [https://docs.qameta.io/allure-report/]:
والآن قم بتنفيذ الأمر التالي:
للتقارير
>تتصرف -f json -o Sample_REST_API_Testing.feature
> خدمة جاذبية
سيؤدي هذا إلى إنشاء تقرير نتائج الاختبار الخاص بك بتنسيق جيد وغني بالمعلومات مثل هذا:
تقرير الاختبار بتنسيق HTML
تقرير اختبار يعرض نتيجة السيناريو الفردية
ملخص
- BDD هو التطوير القائم على السلوك. إنها إحدى تقنيات تطوير البرمجيات الرشيقة.
- أصبح REST أسلوبًا شائعًا جدًا لبناء واجهات برمجة التطبيقات (APIs) في الوقت الحاضر، كما أصبح من المهم أيضًا أتمتة حالات اختبار REST API جنبًا إلى جنب مع حالات اختبار واجهة المستخدم.
- يحتوي BDD على تنسيق لغة طبيعية يصف ميزة أو جزء من الميزة مع أمثلة تمثيلية للنتائج المتوقعة
- يحدد إطار العمل وظيفة الخطوة من خلال المزخرفات المتطابقة مع مسند ملف الميزة
- أمثلة على أطر اختبار BDD: 1) Cucumber 2) SpecFlow 3) الكم 4) JBehave 5) Codeception






