given validation

This commit is contained in:
Oleg Pidsadnyi 2013-09-20 22:48:40 +02:00
parent e121f634ec
commit 6cd91e6e75
11 changed files with 58 additions and 20 deletions

View File

@ -146,7 +146,7 @@ class Feature(object):
if mode == SCENARIO:
self.scenarios[line] = scenario = Scenario(line)
else:
scenario.add_step(line)
scenario.add_step(step_name=line, step_type=mode)
@classmethod
def get_feature(cls, filename):
@ -176,7 +176,12 @@ class Scenario(object):
self.params = set()
self.steps = []
def add_step(self, step):
"""Add step."""
self.params.update(get_step_params(step))
self.steps.append(step)
def add_step(self, step_name, step_type):
"""Add step to the scenario.
:param step_name: Step name.
:param step_type: Step type.
"""
self.params.update(get_step_params(step_name))
self.steps.append((step_name, step_type))

View File

@ -18,6 +18,7 @@ from _pytest import python
from pytest_bdd.feature import Feature # pragma: no cover
from pytest_bdd.steps import recreate_function
from pytest_bdd.types import GIVEN
class ScenarioNotFound(Exception): # pragma: no cover
@ -28,6 +29,14 @@ class NotEnoughScenarioParams(Exception): # pragma: no cover
"""Scenario function doesn't take enough parameters in the arguments."""
class StepTypeError(Exception): # pragma: no cover
"""Step definition is not of the type expected in the scenario."""
class GivenAlreadyUsed(Exception): # pragma: no cover
"""Fixture that implements the Given has been already used."""
def _find_step_function(request, name):
"""Match the step defined by the regular expression pattern.
@ -92,10 +101,29 @@ def scenario(feature_name, scenario_name):
)
)
givens = set()
# Execute scenario steps
for step in scenario.steps:
step_func = _find_step_function(request, step)
for step_name, step_type in scenario.steps:
step_func = _find_step_function(request, step_name)
# Check the step types are called in the correct order
if step_func.step_type != step_type:
raise StepTypeError('Wrong step type "{0}", expected {1}.'.format(step_func.step_type, step_type))
# Check if the fixture that implements given step has not been yet used by another given step
if step_type == GIVEN:
if step_func.__name__ in givens:
raise GivenAlreadyUsed(
'Fixture "{0}" that implements this given step "{1}" has been already used.'.format(
step_func.__name__, step_name,
)
)
givens.add(step_func.__name__)
# Get the step argument values
kwargs = dict((arg, request.getfuncargvalue(arg)) for arg in inspect.getargspec(step_func).args)
# Execute the step
step_func(**kwargs)
_scenario.pytestbdd_params = set()

View File

@ -48,7 +48,7 @@ PY3 = sys.version_info[0] >= 3 # pragma: no cover
class StepError(Exception): # pragma: no cover
"""Step declaration error."""
RE_TYPE = type(re.compile(''))
RE_TYPE = type(re.compile('')) # pragma: no cover
def given(name, fixture=None):
@ -64,8 +64,12 @@ def given(name, fixture=None):
if fixture is not None:
module = get_caller_module()
func = lambda: lambda request: request.getfuncargvalue(fixture)
contribute_to_module(module, remove_prefix(name), pytest.fixture(func))
step_func = lambda request: request.getfuncargvalue(fixture)
step_func.step_type = GIVEN
step_func.__name__ = fixture
func = pytest.fixture(lambda: step_func)
func.__doc__ = 'Alias for the "{0}" fixture.'.format(fixture)
contribute_to_module(module, remove_prefix(name), func)
return _not_a_fixture_decorator
return _step_decorator(GIVEN, name)
@ -134,12 +138,13 @@ def _step_decorator(step_type, step_name):
step_func.__doc__ = func.__doc__
step_func.__name__ = step_name
step_func.step_type = step_type
@pytest.fixture
def lazy_step_func():
return step_func
# Preserve a docstring
# Preserve the docstring
lazy_step_func.__doc__ = func.__doc__
if pattern:

View File

@ -1,6 +1,5 @@
Scenario: Every step takes a parameter with the same name
Given I have 1 Euro
#And I have 2 Euro
When I pay 2 Euro
And I pay 1 Euro
Then I should have 0 Euro

View File

@ -1,4 +1,4 @@
Scenario: Executed with steps matching regex step definitons
Scenario: Executed with steps matching step definitons with arguments
Given I have a foo fixture with value "foo"
And there is a list
When I append 1 to the list

View File

@ -1,7 +1,10 @@
from pytest_bdd import scenario, given, then
test_steps = scenario('regex.feature', 'Executed with steps matching regex step definitons')
test_steps = scenario(
'args.feature',
'Executed with steps matching step definitons with arguments',
)
@given('I have a foo fixture with value "foo"')

View File

@ -4,14 +4,13 @@ from pytest_bdd import scenario, given, when, then
test_steps = scenario(
'regex_steps.feature',
'args_steps.feature',
'Every step takes a parameter with the same name'
)
@pytest.fixture
def values():
#return ['1', '2', '2', '1', '0', '999999']
return ['1', '2', '1', '0', '999999']

View File

@ -5,18 +5,17 @@ indexserver=
pypi = https://pypi.python.org/simple
[testenv]
commands= py.test --pep8 --junitxml={envlogdir}/junit-{envname}.xml
commands= py.test tests --pep8 --junitxml={envlogdir}/junit-{envname}.xml
deps = -r{toxinidir}/requirements-testing.txt
[testenv:py27-coverage]
commands= py.test --cov=pytest_bdd --pep8 --junitxml={envlogdir}/junit-{envname}.xml
commands= py.test tests --cov=pytest_bdd --pep8 --junitxml={envlogdir}/junit-{envname}.xml
[testenv:py27-xdist]
basepython=python2.7
commands=
py.test -n3 -rfsxX \
py.test tests -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml
[pytest]
addopts=tests
pep8maxlinelength=120