Skip to content

Commit 9739231

Browse files
committed
docs: expand pytest-bdd example with failing, outline, data carriers, checkout scenarios
1 parent 19b6993 commit 9739231

9 files changed

Lines changed: 183 additions & 10 deletions

File tree

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,60 @@
11
# qase-pytest + pytest-bdd example
22

3-
Reproduces the customer feedback scenario: a single Gherkin login
4-
scenario with three steps, each containing a nested manual step via
5-
`qase.step(...)`.
3+
A runnable demo of the native pytest-bdd integration in qase-pytest.
4+
Exercises every feature of the integration so you can see how each kind
5+
of Gherkin construct is reported in Qase.
66

7-
## Run
7+
## What the example covers
8+
9+
| Feature file | Scenario(s) | Demonstrates |
10+
| --- | --- | --- |
11+
| `login.feature` | Successful login | Basic Given/When/Then with nested `qase.step()` calls — sub-steps appear as children of the Gherkin step. |
12+
| `failing.feature` | A failing assertion in the middle step | A failing Then step. The failed step is marked `failed`; pytest-bdd does not run later steps, but the integration records them as `skipped`. |
13+
| `calculator.feature` | Scenario Outline with 3 example rows | Scenario Outline / Examples — produces three parameterized Qase results for the same scenario. |
14+
| `data_carriers.feature` | Step with a data table and a docstring | DataTable rendered as a markdown table, DocString rendered as a fenced code block — both end up in the step `data` payload. |
15+
| `checkout.feature` | Two scenarios sharing a Background | Background steps run before each scenario and are reported on every scenario's result. Multi-scenario feature with distinct `@qase.id=`, `@qase.suite=` tags per scenario. |
16+
17+
## Recognized scenario tags
18+
19+
Tags must be placed on the `Scenario` line (not the `Feature` line) so
20+
they reach `scenario.tags`:
21+
22+
- `@qase.id=NN` — link to a test case
23+
- `@qase.suite=A.B.C` — override suite chain (dot for nesting)
24+
- `@qase.severity=critical` / `@qase.priority=high` / `@qase.layer=e2e`
25+
- `@qase.ignore` — drop the scenario from the report
26+
- `@qase.muted` — don't let the scenario fail the run
27+
28+
## Run locally (report mode)
829

930
```bash
1031
pip install -r requirements.txt
1132
pytest -v
1233
```
1334

14-
Inspect the produced JSON under `build/qase-report/results/` — the
15-
result has the scenario name as title, the feature/suite hierarchy from
16-
the tag, three top-level Gherkin steps, and one sub-step under each.
35+
5 scenarios execute (one failing on purpose). Inspect the produced JSON
36+
under `build/qase-report/results/`:
37+
38+
- Each result has the scenario name as `title`
39+
- Each result has a suite chain matching the `@qase.suite` tag
40+
- Each result has a list of `steps` mirroring the Gherkin steps in order
41+
- Nested `qase.step(...)` calls (inside step functions) appear as
42+
children of the corresponding Gherkin step
43+
- Failed step has `execution.status: "failed"`; trailing unrun steps
44+
are marked `"skipped"`
45+
- Scenario Outline produces one Qase result per Examples row
46+
47+
## Run against Qase TestOps
48+
49+
Set `mode` to `testops` in `qase.config.json`, and provide credentials
50+
via env:
51+
52+
```bash
53+
export QASE_TESTOPS_API_TOKEN=...
54+
export QASE_TESTOPS_PROJECT=PROJ_CODE
55+
pytest -v
56+
```
1757

18-
To send to Qase TestOps instead, set `mode` to `testops` in
19-
`qase.config.json` and provide `QASE_TESTOPS_API_TOKEN` and
20-
`QASE_TESTOPS_PROJECT` via env.
58+
The TestOps API mode preserves native Gherkin step structure (keyword
59+
+ name + data) and renders steps with their Given/When/Then keywords
60+
in the Qase UI.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Feature: Adding numbers
2+
3+
@qase.id=11 @qase.suite=Math.Outline
4+
Scenario Outline: Adding two numbers
5+
Given I have <a> and <b>
6+
Then their sum is <c>
7+
8+
Examples:
9+
| a | b | c |
10+
| 1 | 2 | 3 |
11+
| 5 | 7 | 12 |
12+
| 0 | 0 | 0 |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Feature: Checkout
2+
3+
Background:
4+
Given the user is signed in
5+
And the cart contains 2 items
6+
7+
@qase.id=13 @qase.suite=Checkout.Success
8+
Scenario: Successful checkout
9+
When the user clicks "Place order"
10+
Then the order is created
11+
12+
@qase.id=14 @qase.suite=Checkout.PaymentDeclined
13+
Scenario: Declined payment
14+
Given the saved card is expired
15+
When the user clicks "Place order"
16+
Then the payment fails with "card_expired"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Feature: Data carriers
2+
3+
@qase.id=12 @qase.suite=API.Payloads
4+
Scenario: Step with a data table and a docstring
5+
Given the following users:
6+
| name | role |
7+
| Alice | admin |
8+
| Bob | user |
9+
When I send the payload:
10+
"""
11+
{"username": "alice", "active": true}
12+
"""
13+
Then the request succeeds
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Feature: Math
2+
3+
@qase.id=10 @qase.suite=Math.Failure @qase.severity=major
4+
Scenario: A failing assertion in the middle step
5+
Given a calculator
6+
When I add 2 and 2
7+
Then the result should be 5
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from pytest_bdd import scenarios, given, then, parsers
2+
3+
scenarios("../features/calculator.feature")
4+
5+
6+
@given(parsers.parse("I have {a:d} and {b:d}"), target_fixture="numbers")
7+
def numbers(a, b):
8+
return a, b
9+
10+
11+
@then(parsers.parse("their sum is {c:d}"))
12+
def check_sum(numbers, c):
13+
assert sum(numbers) == c
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from pytest_bdd import scenarios, given, when, then, parsers
2+
3+
scenarios("../features/checkout.feature")
4+
5+
6+
@given("the user is signed in")
7+
def signed_in():
8+
pass
9+
10+
11+
@given("the cart contains 2 items")
12+
def cart_two_items():
13+
pass
14+
15+
16+
@given("the saved card is expired")
17+
def expired_card():
18+
pass
19+
20+
21+
@when(parsers.parse('the user clicks "{label}"'))
22+
def click(label):
23+
assert label == "Place order"
24+
25+
26+
@then("the order is created")
27+
def order_created():
28+
assert True
29+
30+
31+
@then(parsers.parse('the payment fails with "{reason}"'))
32+
def payment_failure(reason):
33+
assert reason == "card_expired"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from pytest_bdd import scenarios, given, when, then
2+
3+
scenarios("../features/data_carriers.feature")
4+
5+
6+
@given("the following users:")
7+
def users(datatable=None):
8+
# pytest-bdd injects the data table into the step function when a
9+
# parameter named `datatable` is present; ignore it here — the
10+
# purpose of this example is to see the table land in the Qase report.
11+
pass
12+
13+
14+
@when("I send the payload:")
15+
def payload(docstring=None):
16+
pass
17+
18+
19+
@then("the request succeeds")
20+
def request_ok():
21+
assert True
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from pytest_bdd import scenarios, given, when, then
2+
3+
scenarios("../features/failing.feature")
4+
5+
6+
@given("a calculator")
7+
def a_calc():
8+
pass
9+
10+
11+
@when("I add 2 and 2")
12+
def add():
13+
pass
14+
15+
16+
@then("the result should be 5")
17+
def assert_five():
18+
assert 2 + 2 == 5

0 commit comments

Comments
 (0)