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.

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ő:
- Az átutalásnak akkor kell megtörténnie, ha elegendő egyenleg van a forrásszámlán.
- Az átutalásnak meg kell történnie, ha a rendeltetési légkondicionálás adatai helyesek
- 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.
- Az átutalásnak akkor is meg kell történnie, ha munkaszüneti nap van.
- 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:
- Töltse le és telepítse Python 3 -tól https://www.python.org/
- A Behave telepítéséhez futtassa a következő parancsot a parancssorban:
pip install behave- SDI: PyCharm A Közösségi Kiadást itt használjuk — https://www.jetbrains.com/pycharm/download/
Projekt beállítása:
- Új projekt létrehozása
- Hozza létre a következő könyvtárstruktúrát
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:
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:
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:
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:
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.
- 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.
- 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á.
- 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é. - 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. - 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. - 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.
- 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.
contextobjektum, így az állapot tisztán visszaáll a forgatókönyvek között. - Címkézési forgatókönyvek szelektív futtatásokhoz. Olyan címkék, mint például
@smokeor@regressionlehető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.






