forked from test_framework/pytest-bdd
cleanup unnecessary code, move to more clean implementation
This commit is contained in:
parent
3011f19ab3
commit
1f9bbc8cde
16
README.md
16
README.md
|
@ -108,16 +108,17 @@ As you can see we don't use Scenario Outline, but use just Scenario, just becaus
|
|||
|
||||
The code will look like:
|
||||
|
||||
test_reuse = scenario(
|
||||
# here we use pytest power to parametrize test
|
||||
@pytest.mark.parametrize(
|
||||
['start', 'eat', 'left'],
|
||||
[(12, 5, 7)])
|
||||
@scenario(
|
||||
'parametrized.feature',
|
||||
'Parametrized given, when, thens',
|
||||
# here we tell scenario about the parameters, it's not possible to get them automatically, as
|
||||
# feature files are parsed on test runtime, not import time
|
||||
params=['start', 'eat', 'left']
|
||||
)
|
||||
|
||||
# here we use pytest power to parametrize test
|
||||
test_reuse = pytest.mark.parametrize(['start', 'eat', 'left'], [(12, 5, 7)])(test_reuse)
|
||||
# note that we should receive same arguments in function that we use for test parametrization
|
||||
def test_parametrized(start, eat, left):
|
||||
"""We don't need to do anything here, everything will be managed by scenario decorator."""
|
||||
|
||||
|
||||
@given('there are <start> cucumbers')
|
||||
|
@ -135,6 +136,7 @@ The code will look like:
|
|||
assert start - eat == left
|
||||
|
||||
|
||||
|
||||
Reuse fixtures
|
||||
================
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ STEP_PREFIXES = {
|
|||
|
||||
COMMENT_SYMBOLS = '#'
|
||||
|
||||
STEP_PARAM_RE = re.compile('\<(.+)\>')
|
||||
STEP_PARAM_RE = re.compile('\<(.+?)\>')
|
||||
|
||||
|
||||
def get_step_type(line):
|
||||
|
|
|
@ -13,16 +13,20 @@ test_publish_article = scenario(
|
|||
import inspect # pragma: no cover
|
||||
from os import path as op # pragma: no cover
|
||||
|
||||
from _pytest import python
|
||||
|
||||
from pytest_bdd.feature import Feature # pragma: no cover
|
||||
from pytest_bdd.steps import recreate_function # pragma: no cover
|
||||
from pytest_bdd.steps import recreate_function
|
||||
|
||||
|
||||
class ScenarioNotFound(Exception): # pragma: no cover
|
||||
"""Scenario Not Found"""
|
||||
|
||||
|
||||
def scenario(feature_name, scenario_name, params=()):
|
||||
"""Scenario."""
|
||||
def scenario(feature_name, scenario_name):
|
||||
"""Scenario. May be called both as decorator and as just normal function"""
|
||||
|
||||
def decorator(request):
|
||||
|
||||
def _scenario(request):
|
||||
# Get the feature
|
||||
|
@ -34,16 +38,31 @@ def scenario(feature_name, scenario_name, params=()):
|
|||
try:
|
||||
scenario = feature.scenarios[scenario_name]
|
||||
except KeyError:
|
||||
raise ScenarioNotFound('Scenario "{0}" in feature "{1}" is not found'.format(scenario_name, feature_name))
|
||||
raise ScenarioNotFound(
|
||||
'Scenario "{0}" in feature "{1}" is not found'.format(scenario_name, feature_name))
|
||||
|
||||
if scenario.params != _scenario.pytestbdd_params:
|
||||
raise Exception(scenario.params, _scenario.pytestbdd_params)
|
||||
|
||||
# Execute scenario's steps
|
||||
for step in scenario.steps:
|
||||
func = request.getfuncargvalue(step)
|
||||
kwargs = dict((arg, request.getfuncargvalue(arg)) for arg in inspect.getargspec(func).args)
|
||||
func(**kwargs)
|
||||
step_func = request.getfuncargvalue(step)
|
||||
kwargs = dict((arg, request.getfuncargvalue(arg)) for arg in inspect.getargspec(step_func).args)
|
||||
step_func(**kwargs)
|
||||
|
||||
if params:
|
||||
# add test parameters to function
|
||||
_scenario = recreate_function(_scenario, add_args=params)
|
||||
_scenario.pytestbdd_params = set()
|
||||
|
||||
if isinstance(request, python.FixtureRequest):
|
||||
# we called as a normal function
|
||||
return _scenario(request)
|
||||
|
||||
# we called as a decorator, so modify the returned function to add parameters from a decorated function
|
||||
func_args = inspect.getargspec(request).args
|
||||
if 'request' in func_args:
|
||||
func_args.remove('request')
|
||||
_scenario = recreate_function(_scenario, add_args=func_args)
|
||||
_scenario.pytestbdd_params = set(func_args)
|
||||
|
||||
return _scenario
|
||||
|
||||
return decorator
|
||||
|
|
|
@ -38,7 +38,7 @@ import sys
|
|||
|
||||
import pytest
|
||||
|
||||
from pytest_bdd.feature import remove_prefix
|
||||
from pytest_bdd.feature import remove_prefix, get_step_params
|
||||
from pytest_bdd.types import GIVEN, WHEN, THEN
|
||||
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
|
@ -48,6 +48,10 @@ class StepError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class NotEnoughStepParams(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def given(name, fixture=None):
|
||||
"""Given step decorator.
|
||||
|
||||
|
@ -95,11 +99,10 @@ 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, params=None):
|
||||
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.
|
||||
:param params: Step params.
|
||||
|
||||
:return: Decorator function for the step.
|
||||
|
||||
|
@ -108,8 +111,17 @@ def _step_decorator(step_type, step_name, params=None):
|
|||
"""
|
||||
step_name = remove_prefix(step_name)
|
||||
|
||||
step_params = set(get_step_params(step_name))
|
||||
|
||||
def decorator(func):
|
||||
step_func = func
|
||||
if step_params:
|
||||
step_func_args = inspect.getargspec(step_func).args
|
||||
if step_params.intersection(step_func_args) != step_params:
|
||||
raise NotEnoughStepParams(
|
||||
"""Step "{0}" doesn't have enough parameters declared.
|
||||
Should declare params: {1}, but declared only: {2}""".format(step_name, step_params, step_func_args))
|
||||
|
||||
if step_type == GIVEN:
|
||||
if not hasattr(func, '_pytestfixturefunction'):
|
||||
# avoid overfixturing of a fixture
|
||||
|
@ -158,7 +170,8 @@ def recreate_function(func, module=None, add_args=()):
|
|||
elif arg == 'co_argcount':
|
||||
args.append(getattr(code, arg) + len(add_args))
|
||||
elif arg == 'co_varnames':
|
||||
args.append(tuple(add_args) + getattr(code, arg))
|
||||
co_varnames = getattr(code, arg)
|
||||
args.append(co_varnames[:code.co_argcount] + tuple(add_args) + co_varnames[code.co_argcount:])
|
||||
else:
|
||||
args.append(getattr(code, arg))
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mock
|
||||
pytest-pep8
|
||||
pytest-cov
|
||||
pytest-cache
|
||||
|
|
|
@ -1,16 +1,52 @@
|
|||
import pytest
|
||||
|
||||
from pytest_bdd.steps import when
|
||||
from pytest_bdd.steps import NotEnoughStepParams
|
||||
|
||||
from pytest_bdd import given, then, scenario
|
||||
from pytest_bdd import given, when, then, scenario
|
||||
|
||||
test_reuse = scenario(
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
['start', 'eat', 'left'],
|
||||
[(12, 5, 7)])
|
||||
@scenario(
|
||||
'parametrized.feature',
|
||||
'Parametrized given, when, thens',
|
||||
params=['start', 'eat', 'left']
|
||||
)
|
||||
def test_parametrized(request, start, eat, left):
|
||||
"""Test parametrized scenario."""
|
||||
|
||||
test_reuse = pytest.mark.parametrize(['start', 'eat', 'left'], [(12, 5, 7)])(test_reuse)
|
||||
|
||||
def test_parametrized_given():
|
||||
"""Test parametrized given."""
|
||||
with pytest.raises(NotEnoughStepParams) as exc:
|
||||
@given('there are <some> cucumbers')
|
||||
def some_cucumbers():
|
||||
return {}
|
||||
assert exc.value.args == (
|
||||
'Step "there are <some> cucumbers" doesn\'t have enough parameters declared.\n'
|
||||
'Should declare params: set([\'some\']), but declared only: []',)
|
||||
|
||||
|
||||
def test_parametrized_when():
|
||||
"""Test parametrized when."""
|
||||
with pytest.raises(NotEnoughStepParams) as exc:
|
||||
@when('I eat <some> cucumbers')
|
||||
def some_cucumbers():
|
||||
return {}
|
||||
assert exc.value.args == (
|
||||
'Step "I eat <some> cucumbers" doesn\'t have enough parameters declared.\n'
|
||||
'Should declare params: set([\'some\']), but declared only: []',)
|
||||
|
||||
|
||||
def test_parametrized_then():
|
||||
"""Test parametrized then."""
|
||||
with pytest.raises(NotEnoughStepParams) as exc:
|
||||
@when('I should have <some> cucumbers')
|
||||
def some_cucumbers():
|
||||
return {}
|
||||
assert exc.value.args == (
|
||||
'Step "I should have <some> cucumbers" doesn\'t have enough parameters declared.\n'
|
||||
'Should declare params: set([\'some\']), but declared only: []',)
|
||||
|
||||
|
||||
@given('there are <start> cucumbers')
|
||||
|
|
Loading…
Reference in New Issue