Co je BDD testování? Rámec pro behaviorálně řízený vývoj
⚡ Chytré shrnutí
Testování BDD popisuje chování aplikace v jednoduchém jazyce typu „daný-když-pak“, takže analytici, vývojáři a testeři sdílejí jednu specifikaci. Tento návod aplikuje tento přístup na testování REST API pomocí funkce Behave, tedy funkce Behave. Python framework, zahrnující nastavení, soubory funkcí, implementace kroků, provádění a reporting.

Co je testování BDD (Behavior Driven Development)?
BDD (Behavior-driven development) Testování je technika agilního vývoje softwaru a rozšíření TDD, tj. Test Driven Development (vývoj řízený testy). V BDD jsou testovací případy psány v přirozeném jazyce, který dokážou číst i neprogramátoři.
Jak funguje testování BDD?
Představte si, že máte za úkol vytvořit modul pro převod finančních prostředků v aplikaci Net Banking.
Existuje několik způsobů, jak to otestovat:
- Převod finančních prostředků by měl proběhnout, pokud je na zdrojovém účtu dostatečný zůstatek.
- Převod prostředků by měl proběhnout, pokud jsou podrobnosti o klimatizaci správné
- Převod finančních prostředků by měl proběhnout, pokud je heslo transakce / kód RSA / bezpečnostní ověření zadané uživatelem správné.
- Převod finančních prostředků by měl proběhnout i v případě státního svátku.
- Převod prostředků by měl proběhnout k budoucímu datu stanovenému majitelem účtu
Jedno Scénář testu stává se propracovanějším a komplexnějším, když vezmeme v úvahu další prvky, jako je převod částky X po dobu Y dnů nebo měsíců, zastaveníping plánovaný převod, když celková částka dosáhne Z, a tak dále.
Obecnou tendencí vývojářů je vyvíjet funkce a testovací kód psát až později. Jak je patrné z výše uvedeného případu, Testovací případ vývoj je zde složitý, takže developer odloží Testování až do vydání, kdy se provádí rychlé, ale neúčinné testování.
Aby se tento problém překonal, byl vytvořen Behaviorálně řízený vývoj (BDD). Ten vývojářům usnadňuje celý proces testování.
V BDD, cokoli napíšete, musí jít do Daný-když-pak kroky. Uvažujme stejný příklad výše v 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
Tento formulář se snadno píše, čte a rozumí mu. Zahrnuje všechny možné testovací případy pro modul převodu finančních prostředků a lze jej rychle upravit, aby vyhovoval většímu počtu požadavků. Zároveň se čte jako živá dokumentace k modulu. Protože BDD vzešel z TDD, je vhodné si rozdíl mezi nimi vyjasnit, než se přesuneme k nástrojům.
BDD vs. TDD: Klíčové rozdíly
Oba postupy jsou zaměřeny na testování jako první a oba zkracují zpětnovazební smyčky. Liší se v tom, kdo testy píše, jaký jazyk tyto testy používají a kterou vrstvu aplikace popisují.
| Vzhled | TDD (vývoj řízený testy) | BDD (vývoj řízený chováním) |
|---|---|---|
| Soustředit | Jak interně funguje jednotka kódu | Jak se systém chová z pohledu uživatele |
| Jazyk | Tvrzení programovacího jazyka | Scénáře „Dané-Když-Pak“ v přirozeném jazyce |
| Hlavní autor | Vývojář | Obchodní analytik, produktový vlastník, tester a vývojář společně |
| Readable od neprogramátorů | Ne | Ano |
| Typický rozsah | Úroveň jednotky | Funkce, API a úroveň akceptace |
| Běžné nástroje | JUnit, pytest, NUnit | Chovej se, Cucumber, SpecFlow, JBehave |
Tyto dvě věci se spíše doplňují než soupeří. Týmy si obvykle udržují TDD pro návrh na úrovni jednotek a přidat scénáře BDD, které popisují chování, které zúčastněné strany skutečně schvalují. Protože koncové body REST se nacházejí přesně na této akceptační vrstvě, jsou přirozeně vhodné pro BDD.
Co je testování REST API?
Vzhledem k tomu, že se REST stal populárním stylem pro tvorbu API, automatizace testovacích případů REST API spolu s testovacími případy uživatelského rozhraní se stala stejně důležitou. REST API testování zahrnuje testování akcí CRUD (Create-Read-Update-Delete) s metodami POST, GET, PUT a DELETE.
Co je Behave?
Behave je jedním z populárních Python Testovací frameworky BDD. Zde je návod, jak funguje Behave:
- Soubory funkcí jsou napsány vaším obchodním analytikem, sponzorem nebo kýmkoli, kdo je vlastníkem scénářů chování. Soubor funkcí používá formát přirozeného jazyka popisující funkci nebo část funkce s reprezentativními příklady očekávaných výsledků.
- Tyto kroky scénáře jsou namapovány na implementace kroků napsané v Python.
- Volitelně ovládací prvky prostředí spouštějí kód před a po krocích, scénářích, funkcích nebo celém spuštění.
Po vyjasnění rolí jednotlivých souborů lze nyní framework nainstalovat.
Nastavení testovacího rámce BDD Chovej se na Windows
Instalace:
- Stažení a instalace Python 3 z https://www.python.org/
- Spusťte následující příkaz na příkazovém řádku pro instalaci Behave
pip install behave- SDI: PyCharm Zde se používá komunitní edice – https://www.jetbrains.com/pycharm/download/
Nastavení projektu:
- Vytvořit nový projekt
- Vytvořte následující adresářovou strukturu
Snímek obrazovky výše ukazuje rozvržení, které Behave očekává: a funkce adresář obsahující soubory funkcí a vnořený kroky adresář, který obsahuje Python implementace. Behave vyhledává obě složky podle názvu, takže názvy složek se musí přesně shodovat.
Soubory funkcí:
Nyní sestavme soubor s funkcemi Sample_REST_API_Testing.feature, přičemž touto funkcí jsou operace CRUD na službě „příspěvky“.
Tento příklad používá https://jsonplaceholder.typicode.com/ ukázka příspěvku REST služba, bezplatné falešné API, které přijímá požadavky na zápis a vrací realistické odpovědi bez ukládání změn.
Příklad scénáře 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
Podobně můžete zbývající scénáře zapsat takto:
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"
Kroky implementace
Nyní můžete pro kroky funkcí použité ve výše uvedených scénářích napsat implementace v Python soubory v adresáři „steps“.
Framework Behave identifikuje funkci step porovnáváním dekorátorů s predikátem souboru funkcí. Například Vzhledem k Predikát ve scénáři souboru funkcí hledá krokovou funkci nesoucí @given dekoratér. Stejné párování se děje i pro Kdy a PakV případě 'But' a 'And' používá funkce step stejný dekorátor jako její předchozí krok. Například pokud 'And' následuje za daným, odpovídající dekorátor funkce step je @given.
Například krok When pro POST lze implementovat následovně. Všimněte si, jak "application/json" se předává ze souboru prvků do zástupného symbolu v závorkách – tomu se říká parametrizace.
# 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
Podobně implementace ostatních kroků v kroku Python soubor bude vypadat takto:
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
⚠️ Poznámka: Porovnání stavových kódů s == spíše než is záležitosti. Ten is operátor testuje identitu objektu, nikoli rovnost, a Python 3.8 a novější vyvolávají SyntaxWarning: „je“ s literálem pro daný vzor. Jakékoli tvrzení zapsané jako assert code is 201 by mělo být přepsáno jako assert code == 201.
Provádění testů
Vývoj testovacího skriptu je dokončen, takže spusťme testy. Spusťte soubor s funkcemi na příkazovém řádku spuštěním následujícího příkazu:
:: 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
Výsledky provedení testu se zobrazí takto:
Zobrazení zprávy na konzole
Výstup do konzole je během vývoje pohodlný, ale zúčastněné strany obvykle preferují čitelnou zprávu, kterou poskytuje Allure.
zprávy
Nejprve nainstalujte formátovací program Allure Behave a nástroj příkazového řádku Allure. Formátovací program je Python balíček; nástroj příkazového řádku je ke stažení samostatně, popsaný v Dokumentace zprávy 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
Tím se vygeneruje zpráva o výsledcích testu v prezentovatelném a informativním formátu, jako je tento:
Testovací zpráva ve formátu HTML
Zpráva o testu zobrazující výsledek jednotlivých scénářů
Funkční sada je užitečná pouze tehdy, pokud zůstává čitelná i s růstem API, a právě zde se vyplácí disciplína v souborech funkcí.
Nejlepší postupy pro psaní souborů funkcí Behave
Sada Behave se rychle degraduje, když scénáře popisují kliknutí a datové části místo chování. Níže uvedené postupy udržují soubory funkcí čitelné pro obchodní zainteresované strany a zároveň zachovávají...ping ο Python vrstva udržovatelná pro inženýry.
- Popište chování, ne implementaci. Napište „Za předpokladu, že zákazník má dostatečný zůstatek“, nikoli „Za předpokladu, že sloupec zůstatku se rovná 500“. Soubor funkcí uvádí, co systém dělá; soubor kroků uvádí, jak se to kontroluje.
- Zachovejte jedno chování na scénář. Scénář, který uvádí stavový kód, tělo odpovědi a řádek databáze, je ve skutečnosti tři scénáře. Jejich rozdělení umožňuje, aby selhání přímo ukazovalo na příčinu.
- Přesunout sdílené nastavení na pozadí. Výše uvedený příklad používá
Background: Given I set sample REST API urltakže každý scénář zdědí základnu URL bez opakování. - Parametrizujte místo duplikace. Zástupné symboly v závorkách, jako například
"{request_name}"Funkce typu „nechat jeden krok“ obsluhuje assessiony GET, PUT a DELETE, a proto tento příklad potřebuje mnohem méně definic kroků než scénáře. - Pro varianty dat použijte osnovu scénáře. Pokud je nutné dokázat stejné chování pro několik vstupů,
Examples:tabulka je přehlednější než kopírované scénáře. - Vyhněte se závislostem mezi scénáři. Metoda Behave nezaručuje, že scénář POST se spustí před scénářem GET v každé konfiguraci. Každý scénář by měl vytvořit stav, který potřebuje.
- Nahraďte globální proměnné na úrovni modulů kontextem. Příklad ukládá koncové body a odpovědi do slovníků modulů pro stručnost. V produkčních sadách je ukládejte do slovníků Behave.
contextobjekt, takže stav se mezi scénáři čistě resetuje. - Označte scénáře pro selektivní spuštění. Štítky jako například
@smokeor@regressionpovolitbehave --tags=@smoke, což udržuje zpětnou vazbu v kanálu rychlou.
Aplikace těchto návyků z prvního souboru funkcí udržuje sadu BDD cennou i po uplynutí původních příkladů CRUD. Týmy, které tento přístup dále rozšiřují, jej často kombinují s... Cucumber pro JVM projekty nebo Postman pro průzkumné kontroly API.






