Ce este testarea BDD? Cadrul de dezvoltare bazată pe comportament
⚡ Rezumat inteligent
Testarea BDD descrie comportamentul aplicației într-un limbaj simplu de tip „Give-When-Then” (Daven-Când-Atunci), astfel încât analiștii, dezvoltatorii și testerii să partajeze o singură specificație. Această demonstrație aplică această abordare testării API-ului REST cu Behave. Python cadru de lucru, care acoperă configurarea, fișierele de caracteristici, implementările pașilor, execuția și raportarea.

Ce este testarea BDD (Behavior Driven Development)?
Testare BDD (Behavior-driven development). este o tehnică de dezvoltare software agilă și este o extensie a TDD, adică Test Driven Development (Dezvoltare bazată pe teste). În BDD, cazurile de testare sunt scrise într-un limbaj natural pe care chiar și cei care nu sunt programatori îl pot citi.
Cum funcționează testarea BDD?
Să presupunem că vi s-a atribuit sarcina de a crea un modul de Transfer de Fonduri într-o aplicație de Net Banking.
Există mai multe modalități de a-l testa:
- Transferul de fonduri ar trebui să aibă loc dacă există un sold suficient în contul sursă.
- Transferul de fond ar trebui să aibă loc dacă detaliile a/c de destinație sunt corecte
- Transferul de fonduri ar trebui să aibă loc dacă parola tranzacției / codul RSA / autentificarea de securitate introdusă de utilizator este corectă.
- Transferul de fonduri ar trebui să aibă loc chiar dacă este o zi liberă legală.
- Transferul de fond ar trebui să aibă loc la o dată viitoare stabilită de titularul contului
Scenariu de testare devine mai elaborat și mai complex pe măsură ce luăm în considerare caracteristici suplimentare, cum ar fi transferul sumei X pentru un interval de Y zile sau luni, oprireaping un transfer programat când totalul ajunge la Z și așa mai departe.
Tendința generală a dezvoltatorilor este de a dezvolta funcționalități și de a scrie cod de testare ulterior. După cum este evident în cazul de mai sus, Caz de testare dezvoltarea aici este complexă, așa că dezvoltatorul va amâna Testarea până la lansare, moment în care se efectuează teste rapide, dar ineficiente.
Pentru a depăși această problemă, a fost concepută Dezvoltarea Bazată pe Comportament (BDD). Aceasta facilitează întregul proces de testare pentru un dezvoltator.
În BDD, orice ai scrie trebuie să intre Dat-Când-Atunci pași. Să luăm în considerare același exemplu de mai sus în BDD:
Given that a fund transfer module in net banking application has been developed And I am accessing it with proper authentication When I 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
Acest formular este ușor de scris, citit și înțeles. Acoperă fiecare caz de testare posibil pentru modulul de transfer de fonduri și poate fi modificat rapid pentru a se potrivi mai multor. De asemenea, se citește ca o documentație dinamică pentru modul. Deoarece BDD a apărut din TDD, diferența dintre cele două merită clarificată înainte de a trece la instrumente.
BDD vs. TDD: Diferențe cheie
Ambele practici pun accentul pe testare și scurtează buclele de feedback. Ele diferă prin cine scrie testele, limbajul folosit de aceste teste și stratul aplicației pe care îl descriu.
| Aspect | TDD (Dezvoltare bazată pe teste) | BDD (dezvoltare bazată pe comportament) |
|---|---|---|
| Focus | Cum funcționează intern o unitate de cod | Cum se comportă sistemul din perspectiva utilizatorului |
| Limbă | Aserțiuni în limbajul de programare | Scenarii Dat-Când-Atunci în limbaj natural |
| Autor principal | Dezvoltator | Analist de afaceri, proprietar de produs, tester și dezvoltator împreună |
| Readable de către non-programatori | Nu | Da |
| Domeniu de aplicare tipic | Nivel de unitate | Caracteristică, API și nivel de acceptare |
| Instrumente comune | JUnit, pytest, NUnit | Comporta, Cucumber, SpecFlow, JBehave |
Cele două sunt complementare, nu concurente. Echipele păstrează, de obicei, TDD pentru proiectarea la nivel de unitate și adăugarea de scenarii BDD deasupra pentru a descrie comportamentul pe care părțile interesate îl aprobă efectiv. Deoarece punctele finale REST se află exact la acel nivel de acceptare, ele se potrivesc în mod natural pentru BDD.
Ce este testarea API REST?
Întrucât REST a devenit un stil popular pentru construirea API-urilor, automatizarea cazurilor de testare REST API alături de cazurile de testare UI a devenit la fel de importantă. REST Testare API implică testarea acțiunilor CRUD (Create-Read-Update-Delete) cu metodele POST, GET, PUT și respectiv DELETE.
Ce este Behave?
Behave este una dintre cele populare Python Cadre de testare BDD. Iată cum funcționează Behave:
- Fișierele de caracteristici sunt scrise de analistul de afaceri, sponsor sau de oricine deține scenariile de comportament. Un fișier de caracteristici folosește un format în limbaj natural care descrie o caracteristică sau o parte a unei caracteristici, cu exemple reprezentative ale rezultatelor așteptate.
- Acești pași de scenariu sunt mapați la implementări de pași scrise în Python.
- Opțional, controalele de mediu execută cod înainte și după pași, scenarii, caracteristici sau întreaga execuție.
Odată ce rolurile fiecărui fișier sunt clare, framework-ul poate fi acum instalat.
Configurarea cadrului de testare BDD Behave on Windows
Instalare:
- Descărcați și instalați Python 3 de la https://www.python.org/
- Executați următoarea comandă la promptul de comandă pentru a instala Behave
pip install behave- SDI: PyCharm Ediția Comunitară este folosită aici — https://www.jetbrains.com/pycharm/download/
Configurare proiect:
- Creați un proiect nou
- Creați următoarea structură de directoare
Captura de ecran de mai sus arată aspectul la care se așteaptă Behave: a caracteristici directorul care conține fișierele de caracteristici și un director imbricat paşi directorul care conține Python implementări. Behave descoperă ambele după nume, deci numele folderelor trebuie să se potrivească exact.
Fișiere de caracteristici:
Acum haideți să construim fișierul de caracteristici Sample_REST_API_Testing.feature, cu funcția de operațiuni CRUD pe serviciul „postări”.
Acest exemplu folosește https://jsonplaceholder.typicode.com/ postează un serviciu REST exemplu, o API falsă gratuită care acceptă cereri de scriere și returnează răspunsuri realiste fără a persista modificările.
Exemplu de scenariu POST
Scenario: POST post example -> creating a new post item using the 'posts' service Given I set post posts API endpoint -> prerequisite: sets the URL of the posts service When I set HEADER param request content type as "application/json" And set request body And send POST HTTP request -> the actual test step Then I receive valid HTTP response code 201 And Response body "POST" is non-empty -> verification of the response body
În mod similar, puteți scrie scenariile rămase după cum urmează:
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"
Etape de implementare
Acum, pentru pașii de funcționalitate utilizați în scenariile de mai sus, puteți scrie implementări în Python fișierele din directorul „steps”.
Framework-ul Behave identifică funcția step prin potrivirea decoratorilor cu predicatul fișierului de caracteristici. De exemplu, a Dat predicatul într-un scenariu de fișier de caracteristici caută o funcție pas cu pas care poartă @given decorator. Aceeași potrivire se întâmplă și pentru Atunci când și "Atunci În cazul funcțiilor „Dar” și „Și”, funcția step preia același decorator ca pasul precedent. De exemplu, dacă „Și” urmează după un element dat, decoratorul funcției step corespunzător este @given.
De exemplu, pasul When pentru POST poate fi implementat după cum urmează. Observați cum "application/json" este transmis din fișierul de caracteristici în substituentul între paranteze — aceasta se numește parametrizare.
# Decorator: the braced name captures a value from the feature file @when(u'I Set HEADER param request content type as "{header_content_type}"') def step_impl(context, header_content_type): # Step implementation: set the content type on the request header request_headers['Content-Type'] = header_content_type
În mod similar, implementarea celorlalți pași din etapa Python fișierul va arăta astfel:
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 = 'https://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_content_type}"') def step_impl(context, header_content_type): request_headers['Content-Type'] = header_content_type # "And" or "But" steps are renamed by behave to match their preceding step @when(u'Set request Body') def step_impl(context): request_bodies['POST'] = {"title": "foo", "body": "bar", "userId": "1"} @when(u'Send POST HTTP request') def step_impl(context): # send the request and save the response object response = requests.post(url=api_endpoints['POST_URL'], json=request_bodies['POST'], headers=request_headers) response_texts['POST'] = response.text print("post response :" + response.text) response_codes['POST'] = response.status_code @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'] == 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']) @when(u'Send GET HTTP request') def step_impl(context): response = requests.get(url=api_endpoints['GET_URL'], headers=request_headers) response_texts['GET'] = response.text response_codes['GET'] = response.status_code @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] == 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): response = requests.put(url=api_endpoints['PUT_URL'], json=request_bodies['PUT'], headers=request_headers) response_texts['PUT'] = response.text print("update response :" + response.text) response_codes['PUT'] = response.status_code # 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): response = requests.delete(url=api_endpoints['DELETE_URL']) response_texts['DELETE'] = response.text print("DELETE response :" + response.text) response_codes['DELETE'] = response.status_code # END DELETE
⚠️ Notă: Compararea codurilor de stare cu == mai degrabă decât is contează. Cel/Cea/Cei/Cele is operatorul testează identitatea obiectului, nu egalitatea, și Python 3.8 și versiunile ulterioare ridică o Avertisment sintaxic: „este” cu un literal pentru acel model. Orice aserțiune scrisă ca assert code is 201 ar trebui rescris ca assert code == 201.
Derularea Testelor
Dezvoltarea scriptului de testare este completă, așa că haideți să rulăm testele. Executați următoarea comandă la promptul de comandă pentru a rula fișierul de caracteristici:
:: Run a single feature file with the pretty formatter behave -f pretty features\feature_files_folder\Sample_REST_API_Testing.feature :: Run every feature in the project behave
Aceasta afișează rezultatele execuției testului după cum urmează:
Afișarea raportului pe consolă
Rezultatul din consolă este util în timpul dezvoltării, dar părțile interesate preferă de obicei un raport ușor de citit, pe care îl oferă Allure.
Rapoarte
Mai întâi, instalați formatatorul Allure Behave și instrumentul din linia de comandă Allure. Formatatorul este un Python pachet; instrumentul din linia de comandă este o descărcare separată descrisă în Documentația Raportului Allure.
:: 1. Install the formatter pip install allure-behave :: 2. Run the tests and write raw results to a folder behave -f allure_behave.formatter:AllureFormatter -o reports/allure-results features/ :: 3. Render and open the HTML report allure serve reports/allure-results
Aceasta generează raportul cu rezultatele testelor într-un format prezentabil și informativ, cum ar fi acesta:
Raport de testare în format HTML
Raport de testare care afișează rezultatul scenariului individual
O suită funcțională este utilă doar dacă rămâne lizibilă pe măsură ce API-ul crește, iar aici disciplina fișierelor de caracteristici dă roade.
Cele mai bune practici pentru scrierea fișierelor de caracteristici Behave
O suită Behave se degradează rapid atunci când scenariile descriu clicuri și sarcini utile în loc de comportament. Practicile de mai jos mențin fișierele de caracteristici lizibile pentru părțile interesate din afaceri, păstrând în același timp...ping il Python strat ușor de întreținut de ingineri.
- Descrie comportamentul, nu implementarea. Scrieți „Dacă un client are un sold suficient”, nu „Dacă coloana soldului este egală cu 500”. Fișierul de caracteristici precizează ce face sistemul; fișierul de pași precizează cum se verifică acest lucru.
- Păstrați un singur comportament per scenariu. Un scenariu care afirmă un cod de stare, un corp de răspuns și un rând în baza de date este, de fapt, trei scenarii. Împărțirea lor face ca eșecurile să indice direct cauza.
- Mută configurarea partajată în fundal. Exemplul de mai sus folosește
Background: Given I set sample REST API urlastfel încât fiecare scenariu moștenește baza URL fără a o repeta. - Parametrizați în loc să duplicați. Substituenți între acolade, cum ar fi
"{request_name}"permiteți ca o funcție pas cu un singur pas să deservească aserțiuni GET, PUT și DELETE, motiv pentru care exemplul necesită mult mai puține definiții de pași decât scenariile. - Folosește Schița scenariului pentru variațiile datelor. Când același comportament trebuie demonstrat pentru mai multe intrări, un
Examples:tabelul este mai clar decât scenariile copiate. - Evitați dependențele dintre scenarii. Funcția Behave nu garantează că un scenariu POST rulează înaintea unui scenariu GET în fiecare configurație. Fiecare scenariu ar trebui să creeze starea de care are nevoie.
- Înlocuiți globalele la nivel de modul cu context. Exemplul stochează punctele finale și răspunsurile în dicționarele de module pentru concizie. În suitele de producție, stocați-le pe Behave.
contextobiect, astfel încât starea se resetează perfect între scenarii. - Etichetați scenarii pentru rulări selective. Etichete precum
@smokeor@regressionpermitebehave --tags=@smoke, ceea ce menține feedback-ul rapid din conductă.
Aplicarea acestor obiceiuri din primul fișier de caracteristici menține o suită BDD valoroasă mult dincolo de exemplele CRUD inițiale. Echipele care extind această abordare o combină adesea cu Cucumber pentru proiecte JVM sau Postman pentru verificări exploratorii ale API-ului.






