ما هو اختبار BDD؟ مثال الإطار

ما هو اختبار BDD (التطوير الموجه بالسلوك)؟

اختبار BDD (التطوير المبني على السلوك). هي تقنية لتطوير البرمجيات الرشيقة وهي بمثابة امتداد لـ TDD، أي التطوير المبني على الاختبار. في BDD، تتم كتابة حالات الاختبار بلغة طبيعية يمكن حتى لغير المبرمجين قراءتها.

كيف يعمل اختبار BDD؟

ضع في اعتبارك أنه تم تكليفك بإنشاء وحدة تحويل الأموال في تطبيق Net Banking.

هناك طرق متعددة لاختباره

  1. يجب أن يتم تحويل الأموال إذا كان هناك رصيد كافٍ في الحساب المصدر
  2. يجب أن يتم تحويل الأموال إذا كانت تفاصيل الحساب الوجهة صحيحة
  3. يجب أن يتم تحويل الأموال إذا كانت كلمة مرور المعاملة / رمز RSA / مصادقة الأمان للمعاملة التي أدخلها المستخدم صحيحة
  4. يجب أن يتم تحويل الأموال حتى لو كانت عطلة البنوك
  5. يجب أن يتم تحويل الأموال في تاريخ مستقبلي يحدده صاحب الحساب

استخدم سيناريو الاختبار تصبح أكثر تفصيلاً وتعقيدًا عندما نأخذ في الاعتبار ميزات إضافية مثل مبلغ التحويل 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

تركيب:

إعداد مشروع:

  • إنشاء مشروع جديد
  • إنشاء هيكل الدليل التالي:

إعداد مشروع

ملفات الميزة:

لذلك دعونا نبني ملف الميزات الخاص بنا 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

تقرير الاختبار بتنسيق HTML

تقرير اختبار يعرض نتيجة السيناريو الفردية

ملخص

  • BDD هو التطوير القائم على السلوك. إنها إحدى تقنيات تطوير البرمجيات الرشيقة.
  • أصبح REST أسلوبًا شائعًا جدًا لبناء واجهات برمجة التطبيقات (APIs) في الوقت الحاضر، كما أصبح من المهم أيضًا أتمتة حالات اختبار REST API جنبًا إلى جنب مع حالات اختبار واجهة المستخدم.
  • يحتوي BDD على تنسيق لغة طبيعية يصف ميزة أو جزء من الميزة مع أمثلة تمثيلية للنتائج المتوقعة
  • يحدد إطار العمل وظيفة الخطوة من خلال المزخرفات المتطابقة مع مسند ملف الميزة
  • أمثلة على أطر اختبار BDD: 1) Cucumber 2) SpecFlow 3) الكم 4) JBehave 5) Codeception

تلخيص هذه التدوينة بـ: