Merge pull request #431 from pytest-dev/then-when-target-fixture

Support `target_fixture` in `when` and `then` steps.
This commit is contained in:
Alessio Bogon 2021-07-03 10:30:38 +02:00 committed by GitHub
commit 98f67019de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 6 deletions

View File

@ -3,6 +3,7 @@ Changelog
Unreleased
-----------
- `when` and `then` steps now can provide a `target_fixture`, just like `given` does. Discussion at https://github.com/pytest-dev/pytest-bdd/issues/402.
- Drop compatibility for python 2 and officially support only python >= 3.6.
- Fix error when using `--cucumber-json-expanded` in combination with `example_converters` (marcbrossaissogeti).
- Fix `--generate-missing` not correctly recognizing steps with parsers

View File

@ -359,6 +359,47 @@ it will stay untouched. To allow this, special parameter `target_fixture` exists
In this example existing fixture `foo` will be overridden by given step `I have injecting given` only for scenario it's
used in.
Sometimes it is also useful to let `when` and `then` steps to provide a fixture as well.
A common use case is when we have to assert the outcome of an HTTP request:
.. code-block:: python
# test_blog.py
from pytest_bdd import scenarios, given, when, then
from my_app.models import Article
scenarios("blog.feature")
@given("there is an article", target_fixture="article")
def there_is_an_article():
return Article()
@when("I request the deletion of the article", target_fixture="request_result")
def there_should_be_a_new_article(article, http_client):
return http_client.delete(f"/articles/{article.uid}")
@then("the request should be successful")
def article_is_published(request_result):
assert request_result.status_code == 200
.. code-block:: gherkin
# blog.feature
Feature: Blog
Scenario: Deleting the article
Given there is an article
When I request the deletion of the article
Then the request should be successful
Multiline steps
---------------

View File

@ -61,35 +61,37 @@ def given(name, converters=None, target_fixture=None):
:param name: Step name or a parser object.
:param converters: Optional `dict` of the argument or parameter converters in form
{<param_name>: <converter function>}.
:param target_fixture: Target fixture name to replace by steps definition function
:param target_fixture: Target fixture name to replace by steps definition function.
:return: Decorator function for the step.
"""
return _step_decorator(GIVEN, name, converters=converters, target_fixture=target_fixture)
def when(name, converters=None):
def when(name, converters=None, target_fixture=None):
"""When step decorator.
:param name: Step name or a parser object.
:param converters: Optional `dict` of the argument or parameter converters in form
{<param_name>: <converter function>}.
:param target_fixture: Target fixture name to replace by steps definition function.
:return: Decorator function for the step.
"""
return _step_decorator(WHEN, name, converters=converters)
return _step_decorator(WHEN, name, converters=converters, target_fixture=target_fixture)
def then(name, converters=None):
def then(name, converters=None, target_fixture=None):
"""Then step decorator.
:param name: Step name or a parser object.
:param converters: Optional `dict` of the argument or parameter converters in form
{<param_name>: <converter function>}.
:param target_fixture: Target fixture name to replace by steps definition function.
:return: Decorator function for the step.
"""
return _step_decorator(THEN, name, converters=converters)
return _step_decorator(THEN, name, converters=converters, target_fixture=target_fixture)
def _step_decorator(step_type, step_name, converters=None, target_fixture=None):

View File

@ -1,5 +1,4 @@
import textwrap
import pytest
def test_steps(testdir):
@ -73,6 +72,59 @@ def test_steps(testdir):
result.assert_outcomes(passed=1, failed=0)
def test_all_steps_can_provide_fixtures(testdir):
"""Test that given/when/then can all provide fixtures."""
testdir.makefile(
".feature",
steps=textwrap.dedent(
"""\
Feature: Step fixture
Scenario: Given steps can provide fixture
Given Foo is "bar"
Then foo should be "bar"
Scenario: When steps can provide fixture
When Foo is "baz"
Then foo should be "baz"
Scenario: Then steps can provide fixture
Then foo is "qux"
And foo should be "qux"
"""
),
)
testdir.makepyfile(
textwrap.dedent(
"""\
from pytest_bdd import given, when, then, parsers, scenarios
scenarios("steps.feature")
@given(parsers.parse('Foo is "{value}"'), target_fixture="foo")
def given_foo_is_value(value):
return value
@when(parsers.parse('Foo is "{value}"'), target_fixture="foo")
def when_foo_is_value(value):
return value
@then(parsers.parse('Foo is "{value}"'), target_fixture="foo")
def then_foo_is_value(value):
return value
@then(parsers.parse('foo should be "{value}"'))
def foo_is_foo(foo, value):
assert foo == value
"""
)
)
result = testdir.runpytest()
result.assert_outcomes(passed=3, failed=0)
def test_when_first(testdir):
testdir.makefile(
".feature",