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!