![]()
Artykuł Testy BDD w Pytest czyli jak zbliżyć kod do biznesu to kolejny wpis pozwalający Wam wpływać na jakość tworzonego oprogramowania w procesie developmentu. Testy BDD w Pytest pozwalają tworzyć zrozumiałe i czytelne przypadki testowe przy użyciu języka Gherkin. W tym artykule odpowiemy na pytanie:
W jaki sposób BDD pomaga znaleźć wspólny język testerom, biznesowi i programistom?
Wprowadzenie
BDD, czyli Behavior-Driven Development, to metoda projektowania i testowania funkcjonalności oparta na opisie zachowania systemu z punktu widzenia użytkownika końcowego.
Scenariusze pisane w stylu BDD nie są tylko testami — to czytelna dokumentacja oczekiwań biznesowych, którą rozumie zarówno tester, developer, jak i osoba nietechniczna.
Dla testera oznacza to, że:
- Można pisać testy, które są zrozumiałe także dla osób spoza IT
- Można współtworzyć scenariusze z analitykiem lub właścicielem produktu
- Łatwiej jest wykryć nieścisłości w wymaganiach zanim powstanie kod
- Testy BDD mogą służyć jako żywa dokumentacja — zawsze aktualna i testowana automatycznie
W dalszej części artykułu zostaną przedstawione zalety podejścia BDD.
💡Z jakimi problemami pomagają uporać się Testy BDD w Pytest?
W codziennej pracy zespołów projektowych często pojawiają się nieporozumienia między tym, co zostało zdefiniowane w wymaganiach, a tym, co zostało ostatecznie zaimplementowane. Testerzy mają trudności ze zrozumieniem intencji biznesu, programiści interpretują wymagania po swojemu, a osoby nietechniczne nie potrafią odczytać języka testów automatycznych.
BDD odpowiada na te wyzwania, wprowadzając wspólny, czytelny język opisu funkcjonalności, który łączy wszystkich interesariuszy: testerów, developerów, analityków i biznes.
Dzięki opisowi scenariuszy w formacie Given–When–Then:
- łatwiej zrozumieć, co ma się dziać w aplikacji z perspektywy użytkownika
- szybciej można wykryć luki lub sprzeczności w wymaganiach
- testy stają się czytelną dokumentacją zachowania systemu
🔍 Czym są Testy BDD w Pytest?
Testy BDD (Behavior-Driven Development) opierają się na opisie zachowania systemu z perspektywy użytkownika. Każdy scenariusz testowy pisany jest w formacie Given–When–Then (Zakładając, że – Kiedy – Wtedy), co pozwala opisać oczekiwane działanie funkcji w sposób zrozumiały dla wszystkich członków zespołu.
W Pythonie do implementacji testów BDD często wykorzystuje się bibliotekę pytest w połączeniu z rozszerzeniem pytest-bdd. Pozwala ono na:
- definiowanie scenariuszy w plikach
.feature(w stylu Gherkin), - mapowanie kroków
Given,When,Thenna funkcje testowe w Pythonie, - integrację testów BDD z istniejącym zestawem testów
pytest.
Testy BDD w pytest działają jak zwykłe testy automatyczne, ale ich struktura i sposób opisu sprawiają, że łatwiej je czytać, utrzymywać i omawiać – nawet w gronie osób nietechnicznych.
🐍 Jak pisać Testy BDD w Pytest?
Pisanie testów BDD w pytest wymaga innego podejścia niż tradycyjne testy jednostkowe czy integracyjne. Zamiast skupiać się na strukturze kodu, koncentrujemy się na zachowaniu systemu z punktu widzenia użytkownika.
🔧 Od czego zacząć?
🐍 Zainstaluj bibliotekę pytest-bdd
pip install pytest-bdd
🥒 Utwórz plik z rozszerzeniem .feature
Plik .feature zawiera scenariusze testowe zapisane w języku Gherkin. Wykorzystuje słowa kluczowe takie jak: Feature, Scenario, Given, When, Then, And, But do opisu warunków testowych i oczekiwanych rezultatów.
Poniżej zostanie przedstawiona lista słów kluczowych oraz ich znacznie.
Feature– opisuje funkcjonalność lub moduł, którego dotyczą scenariuszeScenario– pojedynczy przypadek testowy opisujący konkretne zachowanie systemuGiven– definiuje stan początkowy przed wykonaniem akcji (np. użytkownik jest zalogowany)When– opisuje akcję użytkownika lub systemu (np. kliknięcie przycisku, wysłanie formularza)Then– definiuje oczekiwany rezultat lub stan systemu po wykonaniu akcjiAnd– słowo pomocnicze, pozwala dodać kolejne kroki doGiven,When, lubThenBut– alternatywa dlaAndużywana do wskazania wyjątku lub zachowania przeciwnegoBackground– sekcja zawierająca wspólne kroki dla wszystkich scenariuszy w plikuScenario Outline– szablon scenariusza z parametrami, pozwala testować wiele wariantów danych wejściowychExamples– tabela danych używanych wScenario Outlinedo testowania różnych przypadków
Przykładowy plik zawierający scenariusz logowania z nieprawidłowymi danymi
Feature: User Authentication
Scenario: Login with invalid credentials
Given I am on the login page
When I enter an invalid email "invalid@example.com"
And I enter an invalid password "wrongpassword"
And I click the login button
Then I should see an error message "Authentication failed."
✍️ Przygotuj Page Object reprezentujący stronę logowania w aplikacji testowanej
Plik ten reprezentuje warstwę abstrakcji nad interfejsem użytkownika, oddzielając logikę testów od szczegółów technicznych strony. Umożliwia łatwe i czytelne odwoływanie się do elementów strony logowania w scenariuszach testowych BDD.
Przykładowy plik
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException, TimeoutException
class LoginPage:
def __init__(self, browser: WebDriver) -> None:
self.browser = browser
self.email_input = (By.ID, "email")
self.password_input = (By.ID, "passwd")
self.login_button = (By.ID, "SubmitLogin")
self.error_message = (By.XPATH, "//div[contains(@class, 'alert-danger')]")
self.account_section = (By.CLASS_NAME, "account")
def enter_email(self, email: str) -> None:
try:
self.browser.find_element(*self.email_input).send_keys(email)
except NoSuchElementException:
raise Exception("Email input field was not found on the page.")
def enter_password(self, password: str) -> None:
try:
self.browser.find_element(*self.password_input).send_keys(password)
except NoSuchElementException:
raise Exception("Password input field was not found on the page.")
def click_login(self) -> None:
try:
self.browser.find_element(*self.login_button).click()
except NoSuchElementException:
raise Exception("Login button was not found on the page.")
def is_logged_in(self) -> bool:
try:
WebDriverWait(self.browser, 5).until(
EC.visibility_of_element_located(self.account_section)
)
return True
except TimeoutException:
return False
def get_error_message(self) -> str:
try:
return self.browser.find_element(*self.error_message).text.strip()
except NoSuchElementException:
return ""
🧪 Zaimplementuj kroki testowe
Plik z krokami testowymi (steps) łączy scenariusze zapisane w Gherkinie z konkretnymi działaniami w kodzie. Każdy krok (Given, When, Then) jest odwzorowany jako funkcja, która wykonuje operacje na stronie lub sprawdza oczekiwany rezultat. Dzięki temu scenariusze .feature stają się automatycznymi testami wykonującymi rzeczywiste akcje w aplikacji.
Przykładowy plik
import pytest
from pages.login_page import LoginPage
from pytest_bdd import given, parsers, scenarios, then, when
from selenium.webdriver.remote.webdriver import WebDriver
from utils.browser import wait_for_page_load
scenarios("../features/login.feature")
@pytest.fixture
def login_page(browser: WebDriver) -> LoginPage:
return LoginPage(browser)
@given("I am on the login page")
def open_login_page(browser: WebDriver) -> None:
browser.get(
"http://www.automationpractice.pl/index.php?controller=authentication&back=my-account"
)
wait_for_page_load(browser)
@when(parsers.parse('I enter an invalid email "{email}"'))
def enter_invalid_email(login_page: LoginPage, email: str) -> None:
login_page.enter_email(email)
@when(parsers.parse('I enter an invalid password "{password}"'))
def enter_invalid_password(login_page: LoginPage, password: str) -> None:
login_page.enter_password(password)
@when("I click the login button")
def click_login_button(login_page: LoginPage) -> None:
login_page.click_login()
@then(parsers.parse('I should see an error message "{message}"'))
def verify_error_message(login_page: LoginPage, message: str) -> None:
error_message = login_page.get_error_message()
assert (
message in error_message
), f"❌ Expected error message '{message}', but got '{error_message}'"
📁 Struktura projektu powinna wyglądać zgodnie z poniżej przedstawioną
project_root/
│
├── features/
│ └── login.feature
│
├── pages/
│ └── login_page.py
│
├── steps/
└── login_steps.py
📌 Opis katalogów
features/ – tu znajdują się pliki .feature pisane w Gherkinie
steps/ – implementacje kroków scenariuszy (@given, @when, @then)
pages/ – wzorzec Page Object: klasy i metody do operacji na interfejsie użytkownika.
Jak uruchomić test?
Jeśli chcesz uruchomić wszystkie testy w projekcie przeklej poniższe polecenie do termianala
pytest
Jeśli chcesz uruchomić wszystkie scenariusze w katalogu steps skorzystaj z poniższego:
pytest tests/steps/
💣 Dobre praktyki BDD
🛠️ Unikaj zbyt technicznych opisów scenariuszy. Zamiast „klikam przycisk submit”, użyj „wysyłam formularz rejestracji”. Scenariusze mają być zrozumiałe dla każdego członka zespołu.
🛠️ Grupuj scenariusze tematycznie. Jeden plik .feature powinien odpowiadać jednej funkcjonalności lub modułowi, co ułatwia ich przeszukiwanie i zarządzanie.
🛠️ Używaj Background, gdy kroki się powtarzają. Dzięki temu unikniesz duplikacji kodu w scenariuszach i poprawisz ich czytelność.
🛠️ Zadbaj o spójność nazw kroków. Nazwy kroków powinny być jednoznaczne, zwięzłe i powtarzalne. Jeden krok – jedna funkcja.
🛠️ Stosuj parametryzację przy wielu zestawach danych. Jeśli testujesz tę samą funkcję dla różnych danych wejściowych, skorzystaj z Scenario Outline i tabeli Examples. Umożliwia to wielokrotne wykonanie tego samego scenariusza bez duplikowania kodu.
📌 Podsumowanie
Na zakończenie artykułu Artykuł Testy BDD w Pytest czyli jak zbliżyć kod do biznesu to trzeba wskazać, że Testy BDD w Pytest niosą ze sobą wiele praktycznych zalet – zarówno dla zespołów testerskich, jak i deweloperskich czy biznesowych:
- Czytelność testów
Scenariusze pisane w stylu Given–When–Then są zrozumiałe nie tylko dla programistów, ale również dla analityków czy właścicieli produktu. - Lepsza komunikacja
Testy BDD stają się punktem odniesienia w rozmowach o wymaganiach. Pomagają zespołowi pracować na wspólnym „języku funkcjonalności”. - Wcześniejsze wykrywanie błędów w wymaganiach
Tworzenie scenariuszy BDD często ujawnia nieścisłości lub luki w oczekiwaniach jeszcze przed rozpoczęciem implementacji. - Automatyczna dokumentacja
Scenariusze.featuremogą służyć jako żywa dokumentacja – zawsze aktualna i łatwa do śledzenia przez cały cykl życia projektu. - Łatwiejsze utrzymanie testów
Dobrze opisane scenariusze pozwalają szybciej zrozumieć, co test ma robić – nawet po wielu miesiącach.
