Gherkin with Python and Pytest-BDD


Index

  1. Thanks
  1. Pytest-BDD
  1. Initial Setup
    3.1 Introduction
    3.2 Clone Project
    3.3 Setting Up Pytest-BDD
    3.4 Folders
  1. Gherkin
    4.1 Declaration of Parameters in Feature Files
    4.2 Gherkin Scenarios Implementation
  1. Step Definition
    5.1 Scenarios VS Scenario
    5.2 Step Definition Declaration of Parameters
    5.3 Step Definition Implementation
  1. Other Changes
  1. Running Tests
  1. Repository
  1. Bibliography


1. Thanks


2. Pytest-BDD

In this tutorial we will use pytest-bdd.
Pytest-bdd is a plugin for pytest.
Being one of the best and most popular test frameworks in python, pytest also comes with a bunch of other plugins, such as:

  • Pytest-cov (For code coverage).
  • Pytest-html (For html reports).
  • Pytest-xdist (For parallel execution).


3. Initial Setup


3.1 Introduction

For this tutorial you will need previous knowledge that was seen in this tutorial made with python, selenium and pytest.


3.2 Clone Project

We are going to continue from a previous automation project “Scaling Tests with Docker and Python”.
Make sure you clone the right branch so we can start: “tutorial/scale-tests-docker”.

After cloning it, check in the VSCode if you cloned the right branch.


3.3 Setting Up Pytest-BDD

Use pipenv to create a virtual environment for the project and to manage its dependencies.

Open the project root in your “Command Prompt”.

And run the command below.

pipenv install

The pipenv install command will install all the dependency packages specified in the “Pipfile” file.

Use pipenv to install one more dependency package that we will use in this tutorial.

pipenv install pytest-bdd

After installing pytest-bdd you can check that it was added in the “Pipfile” and “Pipfile.lock” file.

Pipfile”:

Pipfile.lock”:


3.4 Folder

Create the “features” and “step_defs” folders inside “tests” in your project.

  • The “features” folder is where the gherkin scenarios are located.
  • The “step_defs” folder is where all the python modules, including conftest and the step definition codes are located.
  • Step definition is the implementation for each of those lines of gherkin.


4. Gherkin

First you have to map and then write into the feature files the gherkin scenarios you planned.
Only after having the scenarios you should implement the step_definition.


4.1 Declaration of Parameters in Feature Files

The declaration of parameters are made with double quotes, ex:

When the user searches for "panda"

The “scenario outline” parameters are declared between <>, ex:

When the user searches for <name>

A parameter written in multiple lines should be declared between triple quotes, ex:

When the user searches for the phrase:
	"""
	Line1,
	Line2,
	Line3.
	"""


4.2 Gherkin Scenarios Implementation

In the feature file below you can see a normal gherkin file structure.

It has three testing scenarios:

  1. The first is a normal scenario receiving a param and checking the results.
  2. The second is a scenario outline.
  3. The third one is a normal scenario with multi line parameters.

The background works almost like a setup function, it  runs before each scenario.

web.feature”:

Feature: DuckDuckGo Web Browsing
    As a web surfer,
    I want to find information online,
    So I can learn new things and get tasks done.
 
    Background:
        Given the DuckDuckGo home page is displayed
 
    Scenario: Basic DuckDuckGo Result Title
        When the user searches for "panda"
        Then results title contains "panda"
 
    Scenario Outline: Basic DuckDuckGo Search
        When the user searches for <name>
        Then results are shown for <found_animal>
 
    Examples: Animals
        | name       | found_animal |
        | panda      | panda        |
        | python     | python       |
        | polar bear | polar bear   |
 
    Scenario: Lengthy DuckDuckGo Search
        When the user searches for the phrase:
            """
            When in the Course of human events, it becomes necessary for one people
            to dissolve the political bands which have connected them with another,
            and to assume among the powers of the earth, the separate and equal
            station to which the Laws of Nature and of Nature's God entitle them,
            a decent respect to the opinions of mankind requires that they should
            declare the causes which impel them to the separation.
            """
        Then one of the results contains "Declaration of Independence"


5. Step Definition


5.1 Scenarios VS Scenario

Inside a step definition file you have to declare what feature is going to be implemented.

There are two options.

  1. First Option.

Declaring and implementing scenarios individually in the step definition.

from pytest_bdd import scenario
 
@scenario('../features/web.feature', "Basic DuckDuckGo Search")
def test_scenario_basic_search():
    pass
 
@scenario('../features/web.feature', "Lengthy DuckDuckGo Search")
def test_scenario_lengthy_search():
    pass

PS: The scenario function names should start with “test_”.

  1. Second Option (The option we are going to use in this tutorial).

The optimized way to declare and implement scenarios is to use “scenarios” instead of “@scenario”.
One of the pros is that implementing the “def” function is not needed.

from pytest_bdd import scenarios
scenarios('../features/web.feature')


5.2 Step Definition Declaration of Parameters

The parameter with double quotes should be declared as below.

@when(parsers.parse('the user searches for "{parameter}"'))

The “scenario outline” and the multi lines params (that use triple quotes) should be declared as below, without the quotes.

@when(parsers.parse('the user searches for {parameter}'))


5.3 Step Definition Implementation

The code below shows it’s possible that a step definition can be used by more than one gherkin scenario.

test_web_steps.py”:

from pytest_bdd import scenarios, given, when, then, parsers
 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 
from pages.search import DuckDuckGoSearchPage
from pages.result import DuckDuckGoResultPage
 
scenarios('../features/web.feature')
 
@given('the DuckDuckGo home page is displayed')
def duckduckgo_home(browser):
    DuckDuckGoSearchPage(browser).load()
    pass
 
@when(parsers.parse('the user searches for "{text}"'))
@when(parsers.parse('the user searches for {text}'))
@when(parsers.parse('the user searches for the phrase:\n{text}'))
def search_phrase(browser, text):
    DuckDuckGoSearchPage(browser).search(text)
 
@then(parsers.parse('results title contains "{phrase}"'))
def search_results_title(browser, phrase):
    assert WebDriverWait(browser, 5).until(EC.title_contains(phrase))
 
@then(parsers.parse('results are shown for {phrase}'))
def results_have_one(browser, phrase):
    results = DuckDuckGoResultPage(browser).result_link_titles()
    assert len(results) > 0
    assert DuckDuckGoResultPage(browser).search_input_value() == phrase
 
@then(parsers.parse('one of the results contains "{phrase}"'))
def search_results(browser, phrase):
    results = DuckDuckGoResultPage(browser).result_link_titles()
    assert any(phrase in s for s in results)


6. Other Changes

If you want to see the tests running, change the “config.json” file to run locally.

config.json”:

{
    "browser": "Chrome",
    "type": "local",
    "implicit_wait": 10,
    "url_remote": "http://127.0.0.1:4444/wd/hub"
}

PS: To successfully run your tests remember to check if your chromedriver or geckodriver are in the same version of the browsers installed in your machine.
Here’s a tutorial of how to install web drivers in your windows machine.


7. Running Tests

The command to run the tests is the same used in the previous tutorials.

pipenv run python -m pytest


8. Repository

I created a new branch called “tutorial/gherkin-pytest-bdd” for this tutorial, click the link below to see it:
https://github.com/LuizGustavoR/intro-selenium-py/tree/tutorial/gherkin-pytest-bdd

The end.


9. Bibliography

Leave a Comment

Your email address will not be published. Required fields are marked *