Mi a BDD tesztelés? Viselkedésvezérelt fejlesztési keretrendszer

⚡ Okos összefoglaló

A BDD tesztelés az alkalmazás viselkedését egyszerű, adott-mikor-akkor nyelven írja le, így az elemzők, fejlesztők és tesztelők egyetlen specifikációt osztanak meg. Ez a bemutató ezt a megközelítést alkalmazza a REST API tesztelésre a Behave, a Python keretrendszer, amely kiterjed a beállításra, a funkciófájlokra, a lépések megvalósítására, a végrehajtásra és a jelentéskészítésre.

  • 🗣️ Alapelv: A viselkedésvezérelt fejlesztés kiterjeszti a tesztvezérelt fejlesztést azáltal, hogy minden forgatókönyvet természetes nyelven fejez ki, amelyet a nem programozók is el tudnak olvasni és jóváhagyhatnak.
  • 🧱 Forgatókönyv felépítése: Az Adott az előfeltételeket határozza meg, a Mikor végrehajtja a műveletet, a Majd pedig az eredményt állítja be, míg az És vagy a De örökli az előző lépés dekorátorát.
  • 🌐 REST lefedettség: A példa teljes CRUD viselkedést gyakorol a POST, GET, PUT és DELETE utasításokon keresztül a nyilvános jsonplaceholder posts szolgáltatáson.
  • 🐍 Keretrendszer beállítása: Behave telepítések pip-en keresztül Python 3, és egy funkciófájlokat tartalmazó funkciókönyvtárat, valamint egy implementációkat tartalmazó lépéscsomagot vár.
  • 🔗 Lépéskötés: Az olyan dekorátorok, mint a @given, @when és @then, megegyeznek a jellemző szövegével, és a zárójeles helyőrzők átadják az értékeket a forgatókönyvből a Python funkciót.
  • ▶ ️ Végrehajtás: A Pretty formázó minden lépéshez színkóddal jelzi a sikeres vagy sikertelen eredményt a konzolon.
  • 📊 Jelentés: Az allure-behave formázó géppel olvasható eredményeket ír, amelyeket az Allure parancssor böngészhető HTML-jelentésként jelenít meg.

Mi a BDD-tesztelés?

Mi az a BDD (Behavior Driven Development) tesztelés?

BDD (behavior-driven development) tesztelés az agilis szoftverfejlesztés egyik technikája, és a TDD, azaz a tesztvezérelt fejlesztés kiterjesztése. A BDD-ben a teszteseteket természetes nyelven írják, amelyet még a nem programozók is el tudnak olvasni.

Hogyan működik a BDD tesztelés?

Tegyük fel, hogy feladatod egy pénzátutalási modul létrehozása egy netbanki alkalmazásban.

Többféleképpen is tesztelhető:

  1. Az átutalásnak akkor kell megtörténnie, ha elegendő egyenleg van a forrásszámlán.
  2. Az átutalásnak meg kell történnie, ha a rendeltetési légkondicionálás adatai helyesek
  3. Az átutalásnak meg kell történnie, ha a felhasználó által megadott tranzakciós jelszó / RSA kód / biztonsági hitelesítés helyes.
  4. Az átutalásnak akkor is meg kell történnie, ha munkaszüneti nap van.
  5. Az átutalásnak a számlatulajdonos által meghatározott jövőbeni időpontban kell megtörténnie

Az Teszt forgatókönyv bonyolultabbá és összetettebbé válik, mivel további funkciókat is figyelembe veszünk, például X összeg átutalását Y napos vagy hónapos időszakra, a leállítástping egy ütemezett átutalás, amikor az összeg eléri a Z-t, és így tovább.

A fejlesztők általános tendenciája, hogy funkciókat fejlesztenek, és tesztkódot csak később írnak. Amint a fenti esetben is látható, Teszt eset a fejlesztés itt összetett, ezért a fejlesztő elhalasztja Tesztelés kiadásáig, ekkor gyors, de hatástalan tesztelést végeznek.

Ennek a problémának a leküzdésére alkották meg a viselkedésvezérelt fejlesztést (BDD). Ez megkönnyíti a teljes tesztelési folyamatot a fejlesztők számára.

A BDD-ben bármit is írsz, bele kell menni Adott-Mikor-Akkor lépések. Tekintsük a fenti példát BDD-ben:

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

Ez az űrlap könnyen megírható, olvasható és érthető. Lefedi az átutalási modul összes lehetséges tesztesetét, és gyorsan módosítható, hogy több elemet is befogadjon. Úgy is olvasható, mint a modul élő dokumentációja. Mivel a BDD a TDD-ből fejlődött ki, érdemes a kettő közötti különbséget tisztázni, mielőtt továbblépnénk az eszközökre.

BDD vs. TDD: Főbb különbségek

Mindkét gyakorlat a tesztelésre összpontosít, és mindkettő lerövidíti a visszacsatolási hurkokat. Abban különböznek, hogy ki írja a teszteket, milyen nyelvet használnak a tesztek, és az alkalmazás melyik rétegét írják le.

Aspect TDD (tesztvezérelt fejlesztés) BDD (viselkedésvezérelt fejlesztés)
Összpontosít Hogyan működik egy kódegység belsőleg Hogyan viselkedik a rendszer a felhasználó szemszögéből
Nyelv Programozási nyelvi állítások Természetes nyelvi adott-mikor-akkor forgatókönyvek
Elsődleges szerző Fejlesztő Üzleti elemző, terméktulajdonos, tesztelő és fejlesztő együtt
Readable nem programozók által Nem Igen
Tipikus hatókör Egységszint Funkció, API és elfogadási szint
Gyakori eszközök JUnit, pytest, NUnit Viselkedik, Cucumber, SpecFlow, JBehave

A kettő inkább kiegészíti, mintsem verseng. A csapatok általában megtartják TDD az egység szintű tervezéshez, és BDD-forgatókönyveket adjunk hozzá a leíró viselkedéshez, amelyet az érdekelt felek ténylegesen jóváhagynak. Mivel a REST végpontok pontosan ezen az elfogadási szinten helyezkednek el, természetes módon illeszkednek a BDD-hez.

Mi az a REST API tesztelés?

Mivel a REST népszerű stílussá vált az API-k építésében, a REST API tesztesetek automatizálása a felhasználói felület teszteseteivel együtt ugyanolyan fontossá vált. API tesztelés A folyamat magában foglalja a CRUD (Create-Read-Update-Delete) műveletek tesztelését a POST, GET, PUT és DELETE metódusokkal.

Mi a Behave?

A Behave az egyik legnépszerűbb Python BDD tesztelési keretrendszerek. Így működnek a Behave függvények:

  • A funkciófájlokat az üzleti elemző, a szponzor vagy a viselkedési forgatókönyvek tulajdonosa írja. A funkciófájl természetes nyelvi formátumot használ, amely egy funkciót vagy annak egy részét írja le, a várható eredmények reprezentatív példáival.
  • Ezek a forgatókönyv-lépések a következő nyelven írt lépés-megvalósításokhoz vannak leképezve: Python.
  • Opcionálisan a környezeti vezérlők kódot futtatnak a lépések, forgatókönyvek, funkciók vagy a teljes futtatás előtt és után.

Miután minden fájl szerepe tisztázódott, a keretrendszer telepíthető.

BDD Testing Framework beállítása Viselkedés bekapcsolva Windows

Telepítés:

Projekt beállítása:

  • Új projekt létrehozása
  • Hozza létre a következő könyvtárstruktúrát

Projekt beállítása

A fenti képernyőkép a Behave által elvárt elrendezést mutatja: a jellemzők a funkciófájlokat tartalmazó könyvtár, és egy beágyazott lépések könyvtár, amely a Python implementációk. A Behave mindkettőt név alapján ismeri fel, így a mappaneveknek pontosan egyezniük kell.

Funkció fájlok:

Most építsük fel a funkciófájlt Sample_REST_API_Testing.feature, a funkció a CRUD műveletek a 'posts' szolgáltatáson.

Ez a példa a https://jsonplaceholder.typicode.com/ közzétesz egy minta REST szolgáltatást, egy ingyenes, hamis API-t, amely írási kéréseket fogad, és realisztikus válaszokat ad vissza a változtatások megőrzése nélkül.

Példa POST forgatókönyv

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

Hasonlóképpen, a fennmaradó forgatókönyveket a következőképpen írhatja le:

Projekt beállítása

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"

A megvalósítás lépései

Most, a fenti forgatókönyvekben használt funkciólépésekhez implementációkat írhat a következő nyelven: Python fájlok a „steps” könyvtárban.

A Behave keretrendszer a step függvényt a dekorátorok és a jellemzőfájl predikátumának összehasonlításával azonosítja. Például egy Adott Egy jellemzőfájl-forgatókönyvben a predikátum egy lépésfüggvényt keres, amely a következőt hordozza: @given dekoratőr. Ugyanez az egyeztetés történik a következővel is: Amikor és a MajdA „De” és az „És” esetében a lépésfüggvény ugyanazt a dekorátort veszi fel, mint az előző lépése. Például, ha az „És” egy Adott utasítást követ, akkor a megfelelő lépésfüggvény dekorátora a következő: @given.

Például a POST When lépése a következőképpen valósítható meg. Figyeljük meg, hogyan "application/json" átadódik a jellemzőfájlból a zárójeles helyőrzőbe – ezt paraméterezésnek nevezzük.

# 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

Hasonlóképpen, a lépés többi lépésének megvalósítása Python a fájl így fog kinézni:

A megvalósítás lépései

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

⚠️ Megjegyzés: Állapotkódok összehasonlítása == helyett is számít. A is az operátor az objektum azonosságát vizsgálja, nem az egyenlőséget, és Python 3.8 és később emelj egy Szintaxisfigyelmeztetés: az „is” karakterláncot konstanssal egészíti ki az adott mintára. Bármely állítás, amely így van megírva assert code is 201 át kell írni, mint assert code == 201.

A tesztek futtatása

A tesztszkript fejlesztése befejeződött, futtassuk a teszteket. A funkciófájl futtatásához hajtsa végre a következő parancsot a parancssorban:

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

Ez a teszt végrehajtásának eredményeit a következőképpen jeleníti meg:

A tesztek futtatása

Jelentés megjelenítése a konzolon

A konzolos kimenet kényelmes a fejlesztés során, de az érdekelt felek általában egy olvasható jelentést részesítenek előnyben, amit az Allure biztosít.

Jelentések

Először telepítsd az Allure Behave formázót és az Allure parancssori eszközt. A formázó egy Python csomag; a parancssori eszköz külön letöltésként tölthető le, a leírás a Allure Jelentés dokumentációja.

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

Ezáltal a teszteredményekről szóló jelentés egy ilyen, reprezentatív és informatív formátumban készül:

Jelentések

Tesztjelentés HTML formátumban

Tesztjelentés HTML formátumban

Tesztjelentés, amely az egyedi forgatókönyv eredményét jeleníti meg

Egy működőképes API csak akkor hasznos, ha olvasható marad az API növekedésével együtt, és itt kifizetődik a funkciófájlok fegyelmezett kezelése.

Bevált gyakorlatok viselkedési jellemzőfájlok írásához

Egy viselkedési csomag gyorsan lebomlik, ha a forgatókönyvek kattintásokat és hasznos adatokat írnak le viselkedés helyett. Az alábbi gyakorlatok a funkciófájlokat olvashatóvá teszik az üzleti érdekelt felek számára, miközben megőrzik a következőket:ping a Python a mérnökök számára karbantartható réteg.

  1. A viselkedést írd le, ne a megvalósítást. Írd azt, hogy „Feltéve, hogy az ügyfélnek elegendő egyenlege van”, ne azt, hogy „Feltéve, hogy az egyenleg oszlopban 500 szerepel”. A funkciófájl leírja, hogy mit csinál a rendszer; a lépésfájl pedig azt, hogy hogyan ellenőrzi a rendszer.
  2. Forgatókönyvönként egy viselkedést tartson meg. Egy olyan forgatókönyv, amely egy állapotkódot, egy válasz törzsét és egy adatbázis sort állít be, valójában három forgatókönyv. Szétválasztásuk esetén a hibák közvetlenül az okra mutatnak rá.
  3. A megosztott beállítások áthelyezése a háttérbe. A fenti példa a következőt használja: Background: Given I set sample REST API url így minden forgatókönyv örökli az alapértéket URL anélkül, hogy megismételné.
  4. Paraméterezés duplikálás helyett. Merevített helykitöltők, mint például "{request_name}" Hagyjuk, hogy egy lépéses függvény GET, PUT és DELETE utasításokat szolgáljon ki, ezért a példa sokkal kevesebb lépésdefiníciót igényel, mint a forgatókönyvek.
  5. Használja a forgatókönyv vázlatát az adatvariációkhoz. Amikor ugyanazt a viselkedést több bemenetre is bizonyítani kell, egy Examples: A táblázat áttekinthetőbb, mint a másolt forgatókönyvek.
  6. Kerülje a forgatókönyvek közötti függőségeket. A Behave nem garantálja, hogy egy POST szcenárió minden konfigurációban egy GET szcenárió előtt lefut. Minden szcenáriónak létre kell hoznia a szükséges állapotot.
  7. Cserélje le a modul szintű globális változókat kontextusra. A példa a rövidség kedvéért modulszótárakban tárolja a végpontokat és a válaszokat. Éles környezetben a Behave modulszótárában tároljuk őket. context objektum, így az állapot tisztán visszaáll a forgatókönyvek között.
  8. Címkézési forgatókönyvek szelektív futtatásokhoz. Olyan címkék, mint például @smoke or @regression lehetővé behave --tags=@smoke, ami gyorsítja a folyamat visszacsatolását.

Ezen szokások alkalmazása az első funkciófájlból a BDD csomagot a kezdeti CRUD példákon túl is értékessé teszi. A megközelítést tovább kiterjesztő csapatok gyakran párosítják a következőkkel: Cucumber JVM projektekhez vagy Postman a feltáró API-ellenőrzésekhez.

GYIK

Mindketten olvasták a Gherkin jellemzőfájljait. Cucumber lépéseket köt hozzá Java, Ruby, vagy JavaScript, míg a Behave a következőhöz köti őket: PythonVálassza ki az alkalmazásveremnek megfelelőt, hogy a lépésdefiníciók újra felhasználhassák a meglévő teszt segédprogramokat.

Igen. A Behave egy nem nulla kilépési kódot ad vissza, ha bármelyik forgatókönyv meghiúsul, tehát JenkinsA , a GitLab CI vagy a GitHub műveletek automatikusan meghiúsíthatják a buildelést. Tegye közzé az Allure eredmények mappáját build-összetevőként jelentéskészítéshez.

Igen. AI Az asszisztensek felhasználói történetekből vagy OpenAPI specifikációból készítenek Adott-Mikor-Aztán forgatókönyveket. RevTekintse meg a hiányzó negatív esetek és üzleti szabályok kimenetét, mivel a generált forgatókönyvek gyakran csak a sikeres utat fedik le.

A mesterséges intelligencia eszközei észlelik a duplikált vagy majdnem duplikált forgatókönyveket, újrafelhasználható paraméteres lépéseket javasolnak, és a valószínűsíthető ok alapján csoportosítják a bizonytalan hibákat. Ez csökkenti a manuális auditálási erőfeszítést, mivel a funkciófájlok a csapatok között sokszorozódnak.

A tokent egyszer kell lekérni az environment.py before_all hookban, tárolni a context objektumban, és minden kérési lépésben Authorization headerként csatolni. A hitelesítő adatokat környezeti változókban kell tárolni, soha nem funkciófájlokban.

Foglald össze ezt a bejegyzést a következőképpen: