pytest-bdd/pytest_bdd/steps.py

124 lines
3.1 KiB
Python
Raw Permalink Normal View History

2013-03-31 09:03:40 +08:00
"""Step decorators.
Example:
@given('I have an article')
def article(author):
return create_test_article(author=author)
@when('I go to the article page')
def go_to_the_article_page(browser, article):
browser.visit(urljoin(browser.url, '/articles/{0}/'.format(article.id)))
@then('I should not see the error message')
def no_error_message(browser):
with pytest.raises(ElementDoesNotExist):
browser.find_by_css('.message.error').first
2013-04-10 07:00:27 +08:00
Multiple names for the steps:
@given('I have an article')
@given('there is an article')
def article(author):
return create_test_article(author=author)
Reusing existing fixtures for a different step name:
given('I have a beautiful article', fixture='article')
2013-03-31 09:03:40 +08:00
"""
2013-04-10 06:54:38 +08:00
import inspect
import sys
2013-03-31 09:03:40 +08:00
import pytest
2013-04-08 01:45:43 +08:00
from pytest_bdd.feature import remove_prefix
from pytest_bdd.types import GIVEN, WHEN, THEN
2013-03-31 09:03:40 +08:00
2013-04-09 04:29:06 +08:00
class StepError(Exception):
pass
2013-04-10 06:54:38 +08:00
def given(name, fixture=None):
"""Given step decorator.
:param name: Given step name.
:param fixture: Optional name of the fixture to reuse.
:raises: StepError in case of wrong configuration.
:note: Can't be used as a decorator when the fixture is specified.
"""
2013-04-12 21:58:14 +08:00
name = remove_prefix(name)
2013-04-10 06:54:38 +08:00
if fixture is not None:
module = get_caller_module()
2013-06-20 15:31:02 +08:00
func = lambda: lambda request: request.getfuncargvalue(fixture)
setattr(module, name, pytest.fixture(func))
2013-04-10 06:54:38 +08:00
return _not_a_fixture_decorator
return _step_decorator(GIVEN, name)
2013-03-31 09:03:40 +08:00
def when(name):
2013-04-10 06:54:38 +08:00
"""When step decorator.
:param name: Step name.
:raises: StepError in case of wrong configuration.
"""
return _step_decorator(WHEN, name)
2013-03-31 09:03:40 +08:00
def then(name):
2013-04-10 06:54:38 +08:00
"""Then step decorator.
:param name: Step name.
:raises: StepError in case of wrong configuration.
"""
return _step_decorator(THEN, name)
2013-03-31 09:03:40 +08:00
2013-04-10 06:54:38 +08:00
def _not_a_fixture_decorator(func):
"""Function that prevents the decoration.
:param func: Function that is going to be decorated.
:raises: `StepError` if was used as a decorator.
"""
raise StepError('Cannot be used as a decorator when the fixture is specified')
def _step_decorator(step_type, step_name):
"""Step decorator for the type and the name.
:param step_type: Step type (GIVEN, WHEN or THEN).
:param step_name: Step name as in the feature file.
2013-03-31 09:03:40 +08:00
:return: Decorator function for the step.
:note: If the step type is GIVEN it will automatically apply the pytest
fixture decorator to the step function.
"""
2013-04-12 21:58:14 +08:00
step_name = remove_prefix(step_name)
2013-03-31 09:03:40 +08:00
def decorator(func):
2013-04-16 16:37:30 +08:00
step_func = func
2013-04-15 23:44:26 +08:00
if step_type == GIVEN:
if not hasattr(func, '_pytestfixturefunction'):
# avoid overfixturing of a fixture
func = pytest.fixture(func)
2013-04-16 16:37:30 +08:00
step_func = lambda request: request.getfuncargvalue(func.func_name)
2013-04-12 21:58:14 +08:00
2013-04-16 16:37:30 +08:00
step_func.__name__ = step_name
setattr(get_caller_module(), step_name, pytest.fixture(lambda: step_func))
2013-03-31 09:03:40 +08:00
return func
2013-04-12 21:58:14 +08:00
2013-03-31 09:03:40 +08:00
return decorator
def get_caller_module(depth=2):
"""Return the module of the caller."""
frame = sys._getframe(depth)
return inspect.getmodule(frame)