Što je BDD testiranje? Okvir za razvoj vođen ponašanjem
⚡ Pametni sažetak
BDD testiranje opisuje ponašanje aplikacije jednostavnim jezikom "Dano-Kada-Onda" tako da analitičari, programeri i testeri dijele jednu specifikaciju. Ovaj vodič primjenjuje taj pristup na REST API testiranje s Behaveom, Python okvir, koji pokriva postavljanje, datoteke značajki, implementacije koraka, izvršavanje i izvještavanje.

Što je BDD (Razvoj vođen ponašanjem) testiranje?
BDD (Razvoj vođen ponašanjem) testiranje je tehnika agilnog razvoja softvera i proširenje TDD-a, tj. Test Driven Developmenta. U BDD-u, testni slučajevi se pišu prirodnim jezikom koji mogu čitati čak i neprogrameri.
Kako funkcionira BDD testiranje?
Zamislite da vam je zadatak stvoriti modul za prijenos sredstava u aplikaciji Net Banking.
Postoji više načina za testiranje:
- Prijenos sredstava trebao bi se izvršiti ako na izvornom računu ima dovoljno sredstava
- Prijenos sredstava trebao bi se izvršiti ako su podaci o odredišnom klima-uređaju točni
- Prijenos sredstava trebao bi se izvršiti ako je lozinka transakcije / RSA kod / sigurnosna autentifikacija koju je korisnik unio ispravna
- Prijenos sredstava trebao bi se izvršiti čak i ako je državni praznik
- Prijenos sredstava trebao bi se izvršiti na datum u budućnosti koji odredi vlasnik računa
The Testni scenarij postaje složenije i složenije kada uzmemo u obzir dodatne značajke kao što je prijenos iznosa X tijekom intervala od Y dana ili mjeseci, zaustavljanjeping planirani prijenos kada ukupni iznos dosegne Z i tako dalje.
Opća tendencija programera je razvijati značajke, a testni kod pisati kasnije. Kao što je vidljivo u gornjem slučaju, Testni slučaj Razvoj ovdje je složen, pa će programer odgoditi Ispitivanje do puštanja u promet, kada se provodi brzo, ali neučinkovito testiranje.
Kako bi se prevladao ovaj problem, osmišljen je razvoj vođen ponašanjem (BDD). On programeru olakšava cijeli proces testiranja.
U BDD, sve što napišete mora ući S obzirom-Kada-Tada korake. Razmotrimo isti gornji primjer u BDD-u:
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
Ovaj obrazac je jednostavan za pisanje, čitanje i razumijevanje. Pokriva svaki mogući testni slučaj za modul prijenosa sredstava i može se brzo izmijeniti kako bi se prilagodio većem broju. Također se čita kao živa dokumentacija za modul. Budući da je BDD proizašao iz TDD-a, razliku između njih vrijedi riješiti prije nego što se prijeđe na alate.
BDD vs TDD: Ključne razlike
Obje prakse prvo stavljaju testiranje i obje skraćuju petlje povratnih informacija. Razlikuju se po tome tko piše testove, koji jezik ti testovi koriste i koji sloj aplikacije opisuju.
| Aspekt | TDD (Razvoj vođen testiranjem) | BDD (Razvoj vođen ponašanjem) |
|---|---|---|
| Fokus | Kako jedinica koda funkcionira interno | Kako se sustav ponaša iz perspektive korisnika |
| Jezik | Tvrđenja programskog jezika | Scenariji prirodnog jezika: Zadano-Kada-Onda |
| Glavni autor | razvijač | Poslovni analitičar, vlasnik proizvoda, tester i programer zajedno |
| Readable od strane neprogramera | Ne | Da |
| Tipičan opseg | Razina jedinice | Značajka, API i razina prihvaćanja |
| Uobičajeni alati | JUnit, pytest, NUnit | Ponašati, Cucumber, SpecFlow, JBehave |
To dvoje se nadopunjuju, a ne natječu. Timovi obično drže TDD za dizajn na razini jedinice i dodajte BDD scenarije na vrh kako biste opisali ponašanje koje dionici zapravo odobravaju. Budući da se REST krajnje točke nalaze točno na tom sloju prihvaćanja, one su prirodno rješenje za BDD.
Što je REST API testiranje?
Kako je REST postao popularan stil za izgradnju API-ja, automatizacija testnih slučajeva REST API-ja uz testne slučajeve korisničkog sučelja postala je jednako važna. REST API testiranje uključuje testiranje CRUD (Create-Read-Update-Delete) akcija s metodama POST, GET, PUT i DELETE.
Što je Behave?
Behave je jedan od popularnih Python BDD testni okviri. Evo kako Behave funkcionira:
- Datoteke značajki piše vaš poslovni analitičar, sponzor ili tko god je vlasnik scenarija ponašanja. Datoteka značajki koristi format prirodnog jezika koji opisuje značajku ili dio značajke, s reprezentativnim primjerima očekivanih ishoda.
- Ovi koraci scenarija mapirani su na implementacije koraka napisane u Python.
- Opcionalno, kontrole okruženja pokreću kod prije i poslije koraka, scenarija, značajki ili cijelog pokretanja.
Nakon što su uloge svake datoteke jasne, okvir se sada može instalirati.
Postavljanje BDD okvira za testiranje Ponašaj se na Windows
Instalacija:
- Preuzmite i instalirajte Python 3 od https://www.python.org/
- Izvršite sljedeću naredbu u naredbenom retku za instalaciju Behavea
pip install behave- SDI: PyCharm Ovdje se koristi Community Edition — https://www.jetbrains.com/pycharm/download/
Postavljanje projekta:
- Stvorite novi projekt
- Izradite sljedeću strukturu direktorija
Gornja snimka zaslona prikazuje izgled koji Behave očekuje: a značajke direktorij koji sadrži datoteke značajki i ugniježđeni koraci imenik koji sadrži Python implementacije. Behave otkriva oboje po imenu, tako da se nazivi mapa moraju točno podudarati.
Datoteke značajki:
Sada izgradimo datoteku značajki Sample_REST_API_Testing.feature, s značajkom CRUD operacija na usluzi 'posts'.
Ovaj primjer koristi https://jsonplaceholder.typicode.com/ primjer objave REST servisa, besplatnog lažnog API-ja koji prihvaća zahtjeve za pisanje i vraća realistične odgovore bez trajnih promjena.
Primjer POST scenarija
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
Slično tome, preostale scenarije možete napisati na sljedeći način:
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"
Implementacija koraka
Sada, za korake značajki korištene u gornjim scenarijima, možete napisati implementacije u Python datoteke unutar direktorija „steps“.
Okvir Behave identificira funkciju koraka uspoređujući dekoratore s predikatom datoteke značajki. Na primjer, S obzirom predikat u scenariju datoteke značajki traži step funkciju koja nosi @given dekorater. Isto podudaranje se događa i za Kada i TadaU slučaju 'Ali' i 'I', funkcija koraka uzima isti dekorater kao i prethodni korak. Na primjer, ako 'I' slijedi nakon danog, odgovarajući dekorater funkcije koraka je @given.
Na primjer, korak When za POST može se implementirati na sljedeći način. Imajte na umu kako "application/json" prenosi se iz datoteke značajki u rezervirano mjesto u zagradama - to se naziva parametrizacija.
# 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
Slično tome, provedba ostalih koraka u koraku Python datoteka će izgledati ovako:
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
⚠️ Napomena: Uspoređivanje statusnih kodova s == više nego is važnosti. The is Operator provjerava identitet objekta, a ne jednakost, i Python 3.8 i kasnije podižu Sintaksno upozorenje: „je“ s doslovnim za taj uzorak. Bilo koja tvrdnja napisana kao assert code is 201 treba prepisati kao assert code == 201.
Izvođenje testova
Razvoj testnog skripta je završen, pa pokrenimo testove. Izvršite sljedeću naredbu u naredbenom retku da biste pokrenuli datoteku značajki:
:: 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
Ovo prikazuje rezultate izvršavanja testa na sljedeći način:
Prikaz izvješća na konzoli
Izlaz iz konzole je praktičan tijekom razvoja, ali dionici obično preferiraju čitljivo izvješće, koje Allure pruža.
Izvješća
Prvo instalirajte Allure Behave formatter i Allure alat za naredbeni redak. Formater je Python paket; alat naredbenog retka je zasebno preuzimanje opisano u Dokumentacija izvješća 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
Ovim se generira izvješće o rezultatima ispitivanja u prezentabilnom i informativnom formatu poput ovog:
Izvješće o ispitivanju u HTML formatu
Izvješće o testiranju koje prikazuje rezultate pojedinačnog scenarija
Radni paket je koristan samo ako ostaje čitljiv kako API raste, što je ono u čemu se isplati disciplina datoteka značajki.
Najbolje prakse za pisanje Behave Feature datoteka
Paket Behave brzo se degradira kada scenariji opisuju klikove i korisne sadržaje umjesto ponašanja. Prakse u nastavku održavaju datoteke značajki čitljivima za poslovne dionike, a istovremeno održavajuping o Python sloj koji inženjeri mogu održavati.
- Opišite ponašanje, a ne implementaciju. Napišite „S obzirom na to da kupac ima dovoljan saldo“, a ne „S obzirom na to da je stupac salda jednak 500“. Datoteka značajki navodi što sustav radi; datoteka koraka navodi kako se to provjerava.
- Zadržite jedno ponašanje po scenariju. Scenarij koji nameće statusni kod, tijelo odgovora i redak baze podataka zapravo su tri scenarija. Njihovo dijeljenje čini da kvarovi izravno upućuju na uzrok.
- Premjesti dijeljene postavke u pozadinu. Gornji primjer koristi
Background: Given I set sample REST API urltako da svaki scenarij nasljeđuje bazu URL bez ponavljanja. - Parametrizirajte umjesto dupliciranja. Zagrade u obliku zagrada kao što su
"{request_name}"Neka funkcija s jednim korakom poslužuje GET, PUT i DELETE tvrdnje, zbog čega primjeru treba puno manje definicija koraka nego scenarijima. - Za varijacije podataka koristite nacrt scenarija. Kada se isto ponašanje mora dokazati za nekoliko ulaznih podataka,
Examples:tablica je jasnija od kopiranih scenarija. - Izbjegavajte međuscenarne ovisnosti. Behave ne jamči da će se POST scenarij pokrenuti prije GET scenarija u svakoj konfiguraciji. Svaki scenarij trebao bi stvoriti stanje koje mu je potrebno.
- Zamijenite globalne vrijednosti na razini modula kontekstom. Primjer pohranjuje krajnje točke i odgovore u rječnicima modula radi kratkoće. U produkcijskim paketima pohranite ih na Behave-ove
contextobjekt tako da se stanje čisto resetira između scenarija. - Označi scenarije za selektivna izvršavanja. Oznake kao što su
@smokeor@regressionDopustitebehave --tags=@smoke, što održava brzu povratnu informaciju cjevovoda.
Primjena ovih navika iz prve datoteke značajki održava BDD paket vrijednim daleko izvan početnih CRUD primjera. Timovi koji dalje proširuju ovaj pristup često ga uparuju s Cucumber za JVM projekte ili Postman za istraživačke API provjere.






