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
|
2013-06-13 21:15:38 +08:00
|
|
|
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
|
2013-06-13 21:15:38 +08:00
|
|
|
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:
|
2013-06-13 21:15:38 +08:00
|
|
|
module = get_caller_module()
|
2013-04-12 21:58:14 +08:00
|
|
|
func = getattr(module, fixture, lambda request: request.getfuncargvalue(fixture))
|
2013-04-15 23:44:26 +08:00
|
|
|
setattr(module, name, pytest.fixture(lambda: 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:
|
2013-05-29 05:09:09 +08:00
|
|
|
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
|
2013-06-13 21:15:38 +08:00
|
|
|
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
|
2013-06-13 21:15:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
def get_caller_module(depth=2):
|
|
|
|
"""Return the module of the caller."""
|
|
|
|
frame = sys._getframe(depth)
|
|
|
|
return inspect.getmodule(frame)
|