Skip to content

Commit

Permalink
Allow to pass scope for given steps. closes #109
Browse files Browse the repository at this point in the history
  • Loading branch information
bubenkoff committed Apr 7, 2015
1 parent 55dac36 commit 83e8a9d
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
@@ -1,6 +1,12 @@
Changelog
=========

2.7.1
-----

- Allow to pass ``scope`` for ``given`` steps (bubenkoff, sureshvv)


2.7.0
-----

Expand Down
30 changes: 30 additions & 0 deletions README.rst
Expand Up @@ -132,6 +132,36 @@ default author.
And there is an article
Given step scope
----------------

If you need your given step to be executed less than once per scenario (for example: once for module, session), you can
pass optional ``scope`` argument:

.. code-block:: python
@given('I have an article', scope='session')
def article(author):
return create_test_article(author=author)
.. code-block:: gherkin
Scenario: I'm the author
Given I'm an author
And I have an article
Scenario: I'm the admin
Given I'm the admin
And there is an article
For this example, step function for 'I have an article' given step will be executed once even though there are 2
scenarios using it.
Note that for other step types, it makes no sense to have scope larger than 'function' (the default) as they represent
an action (when step), and assertion (then step).


Step arguments
--------------

Expand Down
2 changes: 1 addition & 1 deletion pytest_bdd/__init__.py
@@ -1,6 +1,6 @@
"""pytest-bdd public API."""

__version__ = '2.7.0'
__version__ = '2.7.1'

try:
from pytest_bdd.steps import given, when, then
Expand Down
12 changes: 6 additions & 6 deletions pytest_bdd/steps.py
Expand Up @@ -47,7 +47,7 @@ def article(author):
from .parsers import get_parser


def given(name, fixture=None, converters=None):
def given(name, fixture=None, converters=None, scope='function'):
"""Given step decorator.
:param name: Given step name.
Expand All @@ -69,13 +69,13 @@ def step_func(request):
step_func.converters = converters
step_func.__name__ = name
step_func.fixture = fixture
func = pytest.fixture(lambda: step_func)
func = pytest.fixture(scope=scope)(lambda: step_func)
func.__doc__ = 'Alias for the "{0}" fixture.'.format(fixture)
_, name = parse_line(name)
contribute_to_module(module, name, func)
return _not_a_fixture_decorator

return _step_decorator(GIVEN, name, converters=converters)
return _step_decorator(GIVEN, name, converters=converters, scope=scope)


def when(name, converters=None):
Expand Down Expand Up @@ -116,7 +116,7 @@ def _not_a_fixture_decorator(func):
raise StepError('Cannot be used as a decorator when the fixture is specified')


def _step_decorator(step_type, step_name, converters=None):
def _step_decorator(step_type, step_name, converters=None, scope='function'):
"""Step decorator for the type and the name.
:param str step_type: Step type (GIVEN, WHEN or THEN).
Expand All @@ -139,7 +139,7 @@ def decorator(func):
if step_type == GIVEN:
if not hasattr(func, "_pytestfixturefunction"):
# Avoid multiple wrapping of a fixture
func = pytest.fixture(func)
func = pytest.fixture(scope=scope)(func)

def step_func(request):
return request.getfuncargvalue(func.__name__)
Expand All @@ -148,7 +148,7 @@ def step_func(request):

step_func.__name__ = force_encode(parsed_step_name)

@pytest.fixture
@pytest.fixture(scope=scope)
def lazy_step_func():
return step_func

Expand Down
5 changes: 5 additions & 0 deletions tests/steps/given.feature
Expand Up @@ -6,3 +6,8 @@ Scenario: Test reusing root fixture
Scenario: Test reusing local fixture
Given I have alias for foo
Then foo should be "foo"


Scenario: Test session given
Given I have session foo
Then session foo should be "session foo"
17 changes: 16 additions & 1 deletion tests/steps/test_given.py
@@ -1,3 +1,4 @@
"""Given tests."""
import pytest

from pytest_bdd import given, then, scenario
Expand All @@ -12,6 +13,11 @@ def foo():
given("I have an alias to the root fixture", fixture="root")


@given("I have session foo", scope='session')
def session_foo():
return "session foo"


@scenario('given.feature', 'Test reusing local fixture')
def test_given_with_fixture():
pass
Expand All @@ -22,19 +28,28 @@ def test_root_alias():
pass


@scenario('given.feature', 'Test session given')
def test_session_given():
pass


@then('foo should be "foo"')
def foo_is_foo(foo):
assert foo == 'foo'


@then('session foo should be "session foo"')
def session_foo_is_foo(session_foo):
assert session_foo == 'session foo'


@then('root should be "root"')
def root_is_root(root):
assert root == 'root'


def test_decorate_with_fixture():
"""Test given can't be used as decorator when the fixture is specified."""

with pytest.raises(StepError):
@given('Foo', fixture='foo')
def bla():
Expand Down

0 comments on commit 83e8a9d

Please sign in to comment.