Coffee Shop Example
pytest 9.0.3 · pytest-given 0.1.0 ·
Module:
Basic scenario with when/then and a JSON attachment
✓ passed 0ms
Given
a coffee machine
When
I insert $2
Then
I get a coffee
{
  "coffees": 9,
  "price": 2
}
Plain text attachment
✓ passed 0ms
Given
a coffee machine
a printed receipt
Coffee x1     $2.00
----------------
Total:        $2.00
When
the total line is read back
Then
it shows the $2.00 total
Generator fixture with teardown
✓ passed 0ms
Given
a database connection
When
I run a query
Then
the connection is open and the query was logged
Parametrized test (renders as a parameter table)
✓ passed 0ms
Given
a coffee machine
When
I insert ${euros}
Then
the purchase is allowed: {expect}
euros expect status
1 False
2 True
3 True
Parametrize value surfaced as a given (Annotated)
✓ passed 0ms
Given
a coffee machine
an order for a {cup_size} ml cup
When
I brew the cup
Then
the machine has one fewer coffee
cup_size status
200
350
T-string with a non-parametrize value (neutral highlight)
✓ passed 0ms
Given
a coffee machine
I have some coins in hand
When
I insert $5
Then
the machine has 9 coffees left
Brew {cup_size} ml (templated scenario name)
✓ passed 0ms
Given
a coffee machine
When
I brew a {cup_size} ml cup
Then
the machine has one fewer coffee
cup_size status
200
300
Serve a 200 ml cup (one scenario per case) [200]
✓ passed 0ms
Given
a coffee machine
When
I order a 200 ml cup
Then
the machine has one fewer coffee
Serve a 400 ml cup (one scenario per case) [400]
✓ passed 0ms
Given
a coffee machine
the barista reaches for a takeaway cup
When
I order a 400 ml cup
Then
the machine has one fewer coffee
Brew a {flavor} coffee (per-case columns)
✓ passed 0ms
Given
a coffee machine
the machine is primed for {flavor}
brew log
When
I brew a {flavor} coffee
Then
the drink costs {price} euros
flavor brew log price status
vanilla 2
brew log
00:00  purge vanilla line, 40 ml at 92.8C
00:04  dose 18.5 g, grind 12, hopper: vanilla
00:09  pre-infuse at 3.0 bar for 4.0 s
00:13  ramp to 9.0 bar
00:27  stop at 36.0 g yield, ratio 1:1.95
00:31  purge group head, vanilla residue cleared
mocha 3
brew log
00:00  purge mocha line, 40 ml at 92.8C
00:04  dose 18.5 g, grind 12, hopper: mocha
00:09  pre-infuse at 3.0 bar for 4.0 s
00:13  ramp to 9.0 bar
00:27  stop at 36.0 g yield, ratio 1:1.95
00:31  purge group head, mocha residue cleared
Helper functions can record their own steps
✓ passed 0ms
Given
a coffee machine
When
I insert $2
the coin is validated for $2
the balance is updated
Then
the coin is accepted
a coffee is dispensed
the machine state is consistent
{
  "coffees": 9,
  "price": 2
}
Top-level `given` block and deeply nested steps
✓ passed 0ms
Given
a coffee machine
a loyalty card with 5 points
When
I place a large order
I select 3 coffees
I apply loyalty discount
the loyalty card is validated
the discount is calculated
Then
the order is processed correctly
the coffee count is updated
the loyalty points are deducted
the remaining points are valid
{
  "points": 2
}
the machine state is consistent
{
  "coffees": 7,
  "price": 2
}
An expected error, narrated as when + then (when_then)
✓ passed 0ms
Given
a coffee machine
a machine that has sold its last coffee
When
a customer tries to buy a coffee
Then
the machine reports it is sold out
Many tags (the report collapses them behind a +N pill)
✓ passed 0ms
Given
a coffee machine
a loyalty card good for a $1 discount
When
I buy a coffee with the discount
Then
I pay $1
a coffee is dispensed
Failure rendering (intentionally failing)
✗ failed 58ms
Given
a coffee machine
Then
the machine has 20 coffees
assert 10 == 20
site-packages/_pytest/runner.py:353: in from_call
    result: TResult | None = func()
                             ^^^^^^
site-packages/_pytest/runner.py:245: in <lambda>
    lambda: runtest_hook(item=item, **kwds),
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
site-packages/pluggy/_hooks.py:512: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
site-packages/_pytest/logging.py:850: in pytest_runtest_call
    yield
site-packages/_pytest/capture.py:900: in pytest_runtest_call
    return (yield)
            ^^^^^
site-packages/_pytest/skipping.py:268: in pytest_runtest_call
    return (yield)
            ^^^^^
site-packages/_pytest/runner.py:179: in pytest_runtest_call
    item.runtest()
site-packages/_pytest/python.py:1720: in runtest
    self.ihook.pytest_pyfunc_call(pyfuncitem=self)
site-packages/pluggy/_hooks.py:512: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
site-packages/_pytest/python.py:166: in pytest_pyfunc_call
    result = testfunction(**testargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^
examples/coffeeshop/test_coffeeshop.py:251: in test_failing
    assert machine['coffees'] == 20
E   assert 10 == 20
Skipped scenario rendering
○ skipped 0ms
Skipped: demonstrates skipped status
All cases skipped
○ skipped 0ms