Š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.

  • 🗣️ Osnovni princip: Razvoj vođen ponašanjem proširuje razvoj vođen testiranjem izražavajući svaki scenarij prirodnim jezikom koji neprogrameri mogu pročitati i odobriti.
  • 🧱 Struktura scenarija: Gde je postavljeno preduvjete, Kada se izvršava radnja, a Zatim se potvrđuje ishod, dok And ili But nasljeđuje dekorater prethodnog koraka.
  • 🌐 REST pokrivenost: Primjer vježba potpuno CRUD ponašanje putem POST, GET, PUT i DELETE na javnoj jsonplaceholder usluzi objava.
  • 🐍 Postavljanje okvira: Behave se instalira putem pipa Python 3 i očekuje direktorij značajki koji sadrži datoteke značajki plus paket koraka koji sadrži implementacije.
  • 🔗 Povezivanje koraka: Dekoratori poput @given, @when i @then odgovaraju tekstu značajke, a rezervirana mjesta u zagradama prenose vrijednosti iz scenarija u Python funkcija.
  • ▶ ️ Izvršenje: Lijepi formater ispisuje rezultat prolaza ili neuspjeha u boji za svaki korak u konzoli.
  • 📊 Izvješćivanje: Formater allure-behave zapisuje strojno čitljive rezultate koje Allureova naredbena linija prikazuje kao HTML izvješće koje se može pregledavati.

Što je BDD testiranje

Š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:

  1. Prijenos sredstava trebao bi se izvršiti ako na izvornom računu ima dovoljno sredstava
  2. Prijenos sredstava trebao bi se izvršiti ako su podaci o odredišnom klima-uređaju točni
  3. Prijenos sredstava trebao bi se izvršiti ako je lozinka transakcije / RSA kod / sigurnosna autentifikacija koju je korisnik unio ispravna
  4. Prijenos sredstava trebao bi se izvršiti čak i ako je državni praznik
  5. 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:

Postavljanje projekta:

  • Stvorite novi projekt
  • Izradite sljedeću strukturu direktorija

Postavljanje projekta

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:

Postavljanje projekta

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:

Implementacija koraka

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:

Izvođenje testova

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šća

Izvješće o ispitivanju u HTML formatu

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.

  1. 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.
  2. 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.
  3. Premjesti dijeljene postavke u pozadinu. Gornji primjer koristi Background: Given I set sample REST API url tako da svaki scenarij nasljeđuje bazu URL bez ponavljanja.
  4. 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.
  5. Za varijacije podataka koristite nacrt scenarija. Kada se isto ponašanje mora dokazati za nekoliko ulaznih podataka, Examples: tablica je jasnija od kopiranih scenarija.
  6. 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.
  7. 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 context objekt tako da se stanje čisto resetira između scenarija.
  8. Označi scenarije za selektivna izvršavanja. Oznake kao što su @smoke or @regression Dopustite behave --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.

Pitanja i odgovori

Oba čitaju Gherkinove datoteke značajki. Cucumber veže korake za Java, Ruby ili JavaSkripta, dok ih Behave veže za PythonOdaberite onaj koji odgovara vašem aplikacijskom stogu kako bi definicije koraka ponovno koristile postojeće uslužne programe za testiranje.

Da. Behave vraća izlazni kod koji nije nula kada bilo koji scenarij ne uspije, dakle Jenkins, GitLab CI ili GitHub akcije mogu automatski propasti izgradnju. Objavite mapu rezultata Allure kao artefakt izgradnje za izvještavanje.

Da. AI Asistenti izrađuju scenarije "Dano-Kada-Onda" na temelju korisničkih priča ili OpenAPI specifikacije. Revpogledajte izlaz za nedostajuće negativne slučajeve i poslovna pravila, jer generirani scenariji često pokrivaju samo sretan put.

Alati umjetne inteligencije otkrivaju duplicirane ili gotovo duplicirane scenarije, predlažu korake s parametrima za višekratnu upotrebu i grupiraju nestabilne kvarove prema vjerojatnom uzroku. To smanjuje napor ručne revizije jer se datoteke značajki množe među timovima.

Dohvatite token jednom u hook-u environment.py before_all, pohranite ga na objekt konteksta i priložite ga kao zaglavlje autorizacije u svakom koraku zahtjeva. Vjerodajnice čuvajte u varijablama okruženja, nikada u datotekama značajki.

Sažmite ovu objavu uz: