Introduction
Behavior-Driven Development (BDD) is a software development process that enhances communication between developers, testers, and non-technical stakeholders. It uses simple, natural language syntax to describe the behavior of the application, making it easier for everyone to understand the requirements and the expected behavior.
Example of BDD
Consider a simple feature of logging into a web application. In BDD, this might be described in a feature file using Gherkin syntax as follows:
Feature: User Login
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters valid credentials
Then the user should be redirected to the dashboard
In this example, the behavior of the login feature is clearly described in a way that both technical and non-technical stakeholders can understand.
References
- BDD Overview: Cucumber BDD
- pytest Documentation: pytest
- pytest-bdd Documentation: pytest-bdd
- Playwright Documentation: Playwright
- pytest-playwright Documentation: pytest-playwright
Prerequisites
- Basic knowledge of Python
- Familiarity with pytest and web automation concepts
- Python installed on your machine
Step 1: Setting Up the Environment
Installing Required Packages
First, install the necessary packages:
pip install pytest pytest-bdd pytest-playwright
Step 2: Project Structure
Create a structured project directory as follows:
tutorial/
├── features/
│ ├── login.feature
│ ├── search_stock.feature
│ └── create_screen.feature
├── tests/
│ ├── test_a_login.py
│ ├── test_search_stock.py
│ └── test_create_screen.py
├── conftest.py
└── utils/
└── config.py
Step 3: Writing Feature Files
Feature files define the behavior you want to test using Gherkin syntax.
features/login.feature
Feature: Login to Screener.in
Scenario: Log into Screener.in
Given the user is on the login page
When the user logs in with valid credentials
Then the user should be redirected to the dashboard
features/search_stock.feature
Feature: Search for a stock and get the P/E ratio
Scenario Outline: Search for a stock by name and retrieve the P/E ratio
Given the user is logged in
When the user searches for "<stock_name>"
Then the P/E ratio for "<stock_name>" should be displayed
Examples:
| stock_name |
| NESTLEIND |
| PGHH |
| LICI |
| TCS |
| BRITANNIA |
features/create_screen.feature
Feature: Create a new screen for quality stocks
Scenario: Create a new screen with filtering stocks greater than market capital 50000Cr
Given the user is logged in
When the user creates a new screen with filtering stocks greater than market capital 50000Cr
Then the new screen should be created successfully
Step 4: Writing Step Definitions
Step definitions map the steps in your feature files to Python functions.
tests/test_a_login.py
import pytest
from pytest_bdd import scenarios, given, when, then
scenarios('../features/login.feature')
@given('the user is on the login page')
def navigate_to_login_page(page):
page.goto("https://www.screener.in/login/")
@when('the user logs in with valid credentials')
def login_with_valid_credentials(login):
pass # The login fixture handles the login
@then('the user should be redirected to the dashboard')
def verify_dashboard(login):
assert login.url == "https://www.screener.in/dash/"
tests/test_search_stock.py
import pytest
from pytest_bdd import scenarios, given, when, then, parsers
from playwright.sync_api import Page
import time
scenarios('../features/search_stock.feature')
@given('the user is logged in')
def user_logged_in(login):
pass # The login fixture ensures the user is logged in
@when(parsers.parse('the user searches for "{stock_name}"'))
def search_stock(login: Page, stock_name):
login.click('//*[@id="desktop-search"]/div/input')
login.fill('//*[@id="desktop-search"]/div/input', stock_name)
login.click('//*[@id="desktop-search"]/div/div/button')
@then(parsers.parse('the P/E ratio for "{stock_name}" should be displayed'))
def verify_pe_ratio(login: Page, stock_name):
pe_ratio = login.locator('//*[@id="top-ratios"]/li[4]/span[2]')
assert pe_ratio.is_visible()
print(f"P/E Ratio for {stock_name}: {pe_ratio.text_content()}")
time.sleep(5)
tests/test_create_screen.py
import pytest
from pytest_bdd import scenarios, given, when, then
from playwright.sync_api import Page
scenarios("../features/create_screen.feature")
@given("the user is logged in")
def user_logged_in(login):
pass # The login fixture ensures the user is logged in
@when("the user creates a new screen with filtering stocks greater than market capital 50000Cr")
def create_new_screen(login: Page):
login.click("//a[@href='/explore/' and text()='Screens']")
login.click("//a[@class='button button-primary' and @href='/screen/new/']")
login.fill(
'textarea[name="query"]',
"""Market Capitalization > 50000""",
)
login.click("//button[@class='button-primary']")
@then("the new screen should be created successfully")
def verify_new_screen_creation(login: Page):
assert login.locator("text=Nestle India").is_visible()
Step 5: Configuring pytest-playwright
Set up Playwright in your conftest.py
to handle browser instances.
conftest.py
import pytest
from playwright.sync_api import sync_playwright
from utils.config import USERNAME, PASSWORD
@pytest.fixture(scope="session")
def browser():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
yield browser
browser.close()
@pytest.fixture(scope="session")
def context(browser):
context = browser.new_context()
yield context
context.close()
@pytest.fixture(scope="session")
def page(context):
page = context.new_page()
yield page
page.close()
@pytest.fixture(scope="session")
def login(page):
page.goto("https://www.screener.in/login/")
page.fill('input[name="username"]', USERNAME)
page.fill('input[name="password"]', PASSWORD)
page.click('button[type="submit"]')
assert page.url == "https://www.screener.in/dash/"
yield page
utils/config.py
Ensure you have your credentials stored securely:
USERNAME = "your_username"
PASSWORD = "your_password"
Step 6: Running the Tests
To run your tests, simply use the pytest
command:
pytest
Conclusion
This tutorial provided a detailed introduction to setting up and using pytest-bdd
and pytest-playwright
for BDD testing. By following the steps above, you can create robust and readable tests for your web applications.
Feel free to extend this setup to include more complex scenarios and additional utilities as needed. This setup provides a solid foundation for using pytest-bdd
and pytest-playwright
in your projects.
References
- BDD Overview: Cucumber BDD
- pytest Documentation: pytest
- pytest-bdd Documentation: pytest-bdd
- Playwright Documentation: Playwright
- pytest-playwright Documentation: pytest-playwright
By following this guide, you'll be well on your way to implementing effective BDD-style tests for your web applications. Happy testing!
Top comments (1)
amazing tutorial, thank you. exactly what I was looking for. Simple and it just works. Thank you!