BDD Reference#

Gherkin syntax, JIRA ticket types, code templates, and CI/CD configuration.

Gherkin syntax#

Gherkin defines test scenarios using natural language keywords.

Keywords#

Keyword

Purpose

Example

Given

Set up initial state/context

Given the SKA Community Confluence website

When

Perform an action

When I click on the login button

Then

Verify expected outcome

Then I see a login page

And

Continue previous step type

And I am not logged in

But

Negative continuation

But I do not see an error message

Scenario structure#

@XTP-1156
Scenario: Descriptive name of the test
  Given some initial context
  And additional context
  When an action occurs
  And another action
  Then expected outcome
  And additional verification

Scenario Outline (parameterised)#

Use Scenario Outline with an Examples table for multiple test cases:

@XTP-1156
Scenario Outline: Handle invalid inputs
  Given the system is ready
  When I provide <input>
  Then I receive <output>

  Examples:
    | input    | output          |
    | valid    | success         |
    | invalid  | error message   |
    | empty    | validation fail |

JIRA ticket types#

Ticket Type

Project

Purpose

Requirement

L1, L2, IFID, VTS

Source requirements JAMA imports

Feature

Various

User-defined features for PI planning

Test Set

XTP

Groups related tests for a requirement

Test

XTP

Individual BDD test with Gherkin steps

Test Plan

XTP

Describes test conditions (mainly for manual tests)

Test Execution

XTP

Records test run results (CI/CD auto-generates these)

JIRA projects#

Project

Name

URL

L1

Level 1 Requirements

jira.skatelescope.org/projects/L1

L2

Level 2 Requirements

jira.skatelescope.org/projects/L2

IFID

Interface Requirements

jira.skatelescope.org/projects/IFID

VTS

Verification Requirements

jira.skatelescope.org/projects/VTS

XTP

Tests

jira.skatelescope.org/projects/XTP

pytest-bdd code templates#

Basic test structure#

"""BDD tests for [feature name]."""

from pytest_bdd import given, when, then, scenarios, parsers
import pytest

# Load all scenarios from the feature file
scenarios('path/to/feature_file.feature')


@pytest.fixture
def context():
    """Fixture to share data between steps."""
    return {}


@given('initial state description')
def setup_initial_state(context):
    """Set up the test context."""
    context['key'] = 'value'


@when('action description')
def perform_action(context):
    """Execute the action under test."""
    context['result'] = do_something(context['key'])


@then('expected outcome description')
def verify_outcome(context):
    """Assert the expected result."""
    assert context['result'] == expected_value

Parameterised steps#

from pytest_bdd import when, then, parsers

@when(parsers.parse('I provide {input_value}'))
def provide_input(input_value, context):
    """Handle variable input from Examples table."""
    context['input'] = input_value


@when(parsers.re(r'I wait (?P<seconds>\d+) seconds'))
def wait_seconds(seconds, context):
    """Use regex for more complex patterns."""
    import time
    time.sleep(int(seconds))

Shared steps in conftest.py#

# tests/bdd/conftest.py
"""Shared BDD step definitions."""

from pytest_bdd import given
import pytest


@pytest.fixture
def devices():
    """Fixture providing access to test devices."""
    return DeviceManager()


@given('I have a configured subarray')
def configured_subarray(devices):
    """Shared step available to all BDD tests."""
    subarray = devices.get_subarray()
    subarray.configure()
    return subarray

Feature file format#

Structure feature files as follows:

# XTP-494.feature
# Exported from JIRA Test Set XTP-494

@XTP-494
Feature: Configure subarray for imaging scan
  As a telescope operator
  I want to configure a subarray
  So that I can perform an imaging observation

  @XTP-417
  Scenario: Configure subarray with valid parameters
    Given the telescope is in STANDBY state
    And I have a valid configuration file
    When I send the Configure command
    Then the subarray enters READY state
    And the configuration is applied

  @XTP-427
  Scenario: Handle invalid configuration
    Given the telescope is in STANDBY state
    When I send an invalid configuration
    Then the subarray returns an error
    And the subarray remains in STANDBY state

CI/CD configuration#

GitLab CI/CD job for BDD tests with JIRA integration:

bdd-tests:
  stage: test
  script:
    - pip install pytest pytest-bdd
    - pytest tests/bdd/ --cucumber-json=bdd-results.json
  artifacts:
    paths:
      - bdd-results.json
    reports:
      cucumber: bdd-results.json
  only:
    - main
    - master

upload-to-jira:
  stage: deploy
  needs: [bdd-tests]
  script:
    - curl -X POST -H "Authorization: Bearer $XRAY_TOKEN" \
        -H "Content-Type: application/json" \
        -d @bdd-results.json \
        "https://xray.cloud.getxray.app/api/v2/import/execution/cucumber"
  only:
    - main
    - master

Note

Configure the XRAY_TOKEN environment variable in your GitLab project’s CI/CD settings.

Writing effective Gherkin#

Follow these practices for clear, reusable test definitions:

Use consistent phrasing

Check existing tests in JIRA before writing new steps. Consistent wording enables step reuse.

Keep steps atomic

Each step performs one action or checks one thing. Avoid compound steps.

Use domain language

Write steps that stakeholders understand. Avoid technical jargon.

Make steps reusable

Generic steps like Given the telescope is in STANDBY state can be reused across many tests.

Include context

The scenario title and steps together tell the complete story of what the test verifies. Ensure readers understand the test purpose without external documentation.

Example of good vs poor Gherkin:

# Good - clear, reusable steps
Given the telescope is in STANDBY state
When I send the Configure command with valid parameters
Then the subarray enters READY state

# Poor - vague, compound, not reusable
Given everything is set up
When I do the thing and check the result
Then it works