Skip to content

Instantly share code, notes, and snippets.

@curzona
Created November 6, 2013 06:12
Show Gist options
  • Save curzona/7331704 to your computer and use it in GitHub Desktop.
Save curzona/7331704 to your computer and use it in GitHub Desktop.
pytest-bdd 0.6.1 vs 0.6.2 stacktrace comparison.
Scenario: Some determinable business situation
Given some precondition
And some other precondition
When some action by the actor
And some other action
And yet another action
Then some testable outcome is achieved
And something else we can check happens too
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- pytest-2.4.2
plugins: bdd, cache, cov, instafail, pep8, xdist, teamcity-messages
collected 1 items
test_bdd.py F
================================== FAILURES ===================================
___________________ test_SomeDeterminableBusinessSituation ____________________
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
def _scenario(request):
# Get the feature
base_path = request.getfuncargvalue('pytestbdd_feature_base_dir')
feature_path = op.abspath(op.join(base_path, feature_name))
feature = Feature.get_feature(feature_path)
# Get the scenario
try:
scenario = feature.scenarios[scenario_name]
except KeyError:
raise ScenarioNotFound(
'Scenario "{0}" in feature "{1}" is not found.'.format(scenario_name, feature_name)
)
resolved_params = scenario.params.intersection(request.fixturenames)
if scenario.params != resolved_params:
raise NotEnoughScenarioParams(
"""Scenario "{0}" in the feature "{1}" was not able to resolve all declared parameters."""
"""Should resolve params: {2}, but resolved only: {3}.""".format(
scenario_name, feature_name, sorted(scenario.params), sorted(resolved_params),
)
)
givens = set()
# Execute scenario steps
for step 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}" while "{1}" is expected.'.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.fixture in givens:
raise GivenAlreadyUsed(
'Fixture "{0}" that implements this "{1}" given step has been already used.'.format(
step_func.fixture, step.name,
)
)
givens.add(step_func.fixture)
# 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)
C:\Program Files (x86)\Python\2.7\lib\site-packages\pytest_bdd\scenario.py:130:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
> step_func = lambda request: request.getfuncargvalue(func.__name__)
C:\Program Files (x86)\Python\2.7\lib\site-packages\pytest_bdd\steps.py:138:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
argname = 'some_precondition'
def getfuncargvalue(self, argname):
""" Dynamically retrieve a named fixture function argument.
As of pytest-2.3, it is easier and usually better to access other
fixture values by stating it as an input argument in the fixture
function. If you only can decide about using another fixture at test
setup time, you may use this function to retrieve it inside a fixture
function body.
"""
try:
return self._funcargs[argname]
except KeyError:
pass
try:
fixturedef = self._getnextfixturedef(argname)
except FixtureLookupError:
if argname == "request":
return self
raise
self._fixturestack.append(fixturedef)
try:
> result = self._getfuncargvalue(fixturedef)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1257:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
fixturedef = <FixtureDef name='some_precondition' scope='function' baseid='test_bdd.py' module='test_bdd'>
def _getfuncargvalue(self, fixturedef):
try:
return fixturedef.cached_result # set by fixturedef.execute()
except AttributeError:
pass
# prepare request fixturename and param attributes before
# calling into fixture function
argname = fixturedef.argname
node = self._pyfuncitem
mp = monkeypatch()
mp.setattr(self, 'fixturename', argname)
try:
param = node.callspec.getparam(argname)
except (AttributeError, ValueError):
pass
else:
mp.setattr(self, 'param', param, raising=False)
# if a parametrize invocation set a scope it will override
# the static scope defined with the fixture function
scope = fixturedef.scope
try:
paramscopenum = node.callspec._arg2scopenum[argname]
except (KeyError, AttributeError):
pass
else:
if paramscopenum != scopenum_subfunction:
scope = scopes[paramscopenum]
# check if a higher-level scoped fixture accesses a lower level one
if scope is not None:
__tracebackhide__ = True
if scopemismatch(self.scope, scope):
# try to report something helpful
lines = self._factorytraceback()
raise ScopeMismatchError("You tried to access the %r scoped "
"funcarg %r with a %r scoped request object, "
"involved factories\n%s" %(
(scope, argname, self.scope, "\n".join(lines))))
__tracebackhide__ = False
mp.setattr(self, "scope", scope)
# route request.addfinalizer to fixturedef
mp.setattr(self, "addfinalizer", fixturedef.addfinalizer)
try:
# perform the fixture call
> val = fixturedef.execute(request=self)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1311:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureDef name='some_precondition' scope='function' baseid='test_bdd.py' module='test_bdd'>
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
def execute(self, request):
kwargs = {}
for newname in self.argnames:
kwargs[newname] = request.getfuncargvalue(newname)
if self.unittest:
result = self.func(request.instance, **kwargs)
else:
fixturefunc = self.func
# the fixture function needs to be bound to the actual
# request.instance so that code working with "self" behaves
# as expected. XXX request.instance should maybe return None
# instead of raising AttributeError
try:
if request.instance is not None:
fixturefunc = getimfunc(self.func)
if fixturefunc != self.func:
fixturefunc = fixturefunc.__get__(request.instance)
except AttributeError:
pass
result = call_fixture_func(fixturefunc, request, kwargs,
> self.yieldctx)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1769:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
fixturefunc = <function some_precondition at 0x0297B330>
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
kwargs = {}, yieldctx = False
def call_fixture_func(fixturefunc, request, kwargs, yieldctx):
if yieldctx:
if not is_generator(fixturefunc):
fail_fixturefunc(fixturefunc,
msg="yield_fixture requires yield statement in function")
iter = fixturefunc(**kwargs)
next = getattr(iter, "__next__", None)
if next is None:
next = getattr(iter, "next")
res = next()
def teardown():
try:
next()
except StopIteration:
pass
else:
fail_fixturefunc(fixturefunc,
"yield_fixture function has more than one 'yield'")
request.addfinalizer(teardown)
else:
if is_generator(fixturefunc):
fail_fixturefunc(fixturefunc,
msg="pytest.fixture functions cannot use ``yield``. "
"Instead write and return an inner function/generator "
"and let the consumer call and iterate over it.")
> res = fixturefunc(**kwargs)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1713:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
@given('some precondition')
def some_precondition():
print 'some_precondition'
> assert False
E assert False
test_bdd.py:10: AssertionError
------------------------------- Captured stdout -------------------------------
some_precondition
========================== 1 failed in 0.05 seconds ===========================
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- pytest-2.4.2
plugins: bdd, cache, cov, instafail, pep8, xdist, teamcity-messages
collected 1 items
test_bdd.py F
================================== FAILURES ===================================
___________________ test_SomeDeterminableBusinessSituation ____________________
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
> ???
test_bdd.py:132:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
> step_func = lambda request: request.getfuncargvalue(func.__name__)
C:\Program Files (x86)\Python\2.7\lib\site-packages\pytest_bdd\steps.py:138:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
argname = 'some_precondition'
def getfuncargvalue(self, argname):
""" Dynamically retrieve a named fixture function argument.
As of pytest-2.3, it is easier and usually better to access other
fixture values by stating it as an input argument in the fixture
function. If you only can decide about using another fixture at test
setup time, you may use this function to retrieve it inside a fixture
function body.
"""
try:
return self._funcargs[argname]
except KeyError:
pass
try:
fixturedef = self._getnextfixturedef(argname)
except FixtureLookupError:
if argname == "request":
return self
raise
self._fixturestack.append(fixturedef)
try:
> result = self._getfuncargvalue(fixturedef)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1257:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
fixturedef = <FixtureDef name='some_precondition' scope='function' baseid='test_bdd.py' module='test_bdd'>
def _getfuncargvalue(self, fixturedef):
try:
return fixturedef.cached_result # set by fixturedef.execute()
except AttributeError:
pass
# prepare request fixturename and param attributes before
# calling into fixture function
argname = fixturedef.argname
node = self._pyfuncitem
mp = monkeypatch()
mp.setattr(self, 'fixturename', argname)
try:
param = node.callspec.getparam(argname)
except (AttributeError, ValueError):
pass
else:
mp.setattr(self, 'param', param, raising=False)
# if a parametrize invocation set a scope it will override
# the static scope defined with the fixture function
scope = fixturedef.scope
try:
paramscopenum = node.callspec._arg2scopenum[argname]
except (KeyError, AttributeError):
pass
else:
if paramscopenum != scopenum_subfunction:
scope = scopes[paramscopenum]
# check if a higher-level scoped fixture accesses a lower level one
if scope is not None:
__tracebackhide__ = True
if scopemismatch(self.scope, scope):
# try to report something helpful
lines = self._factorytraceback()
raise ScopeMismatchError("You tried to access the %r scoped "
"funcarg %r with a %r scoped request object, "
"involved factories\n%s" %(
(scope, argname, self.scope, "\n".join(lines))))
__tracebackhide__ = False
mp.setattr(self, "scope", scope)
# route request.addfinalizer to fixturedef
mp.setattr(self, "addfinalizer", fixturedef.addfinalizer)
try:
# perform the fixture call
> val = fixturedef.execute(request=self)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1311:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureDef name='some_precondition' scope='function' baseid='test_bdd.py' module='test_bdd'>
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
def execute(self, request):
kwargs = {}
for newname in self.argnames:
kwargs[newname] = request.getfuncargvalue(newname)
if self.unittest:
result = self.func(request.instance, **kwargs)
else:
fixturefunc = self.func
# the fixture function needs to be bound to the actual
# request.instance so that code working with "self" behaves
# as expected. XXX request.instance should maybe return None
# instead of raising AttributeError
try:
if request.instance is not None:
fixturefunc = getimfunc(self.func)
if fixturefunc != self.func:
fixturefunc = fixturefunc.__get__(request.instance)
except AttributeError:
pass
result = call_fixture_func(fixturefunc, request, kwargs,
> self.yieldctx)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1769:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
fixturefunc = <function some_precondition at 0x028321B0>
request = <FixtureRequest for <Function 'test_SomeDeterminableBusinessSituation'>>
kwargs = {}, yieldctx = False
def call_fixture_func(fixturefunc, request, kwargs, yieldctx):
if yieldctx:
if not is_generator(fixturefunc):
fail_fixturefunc(fixturefunc,
msg="yield_fixture requires yield statement in function")
iter = fixturefunc(**kwargs)
next = getattr(iter, "__next__", None)
if next is None:
next = getattr(iter, "next")
res = next()
def teardown():
try:
next()
except StopIteration:
pass
else:
fail_fixturefunc(fixturefunc,
"yield_fixture function has more than one 'yield'")
request.addfinalizer(teardown)
else:
if is_generator(fixturefunc):
fail_fixturefunc(fixturefunc,
msg="pytest.fixture functions cannot use ``yield``. "
"Instead write and return an inner function/generator "
"and let the consumer call and iterate over it.")
> res = fixturefunc(**kwargs)
C:\Program Files (x86)\Python\2.7\lib\site-packages\_pytest\python.py:1713:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
@given('some precondition')
def some_precondition():
print 'some_precondition'
> assert False
E assert False
test_bdd.py:10: AssertionError
------------------------------- Captured stdout -------------------------------
some_precondition
========================== 1 failed in 0.05 seconds ===========================
from pytest_bdd import scenario, given, when, then
@scenario('bdd.feature', 'Some determinable business situation')
def test_SomeDeterminableBusinessSituation():
print 'test_SomeDeterminableBusinessSituation'
@given('some precondition')
def some_precondition():
print 'some_precondition'
assert False
@given('some other precondition')
def some_other_precondition():
print 'some_other_precondition'
@when('some action by the actor')
def some_action_by_the_actor():
print 'some_action_by_the_actor'
@when('some other action')
def some_other_action():
print 'some_other_action'
@when('yet another action')
def yet_another_action():
print 'yet_another_action'
@then('some testable outcome is achieved')
def some_testable_outcome_is_achieved():
print 'some_testable_outcome_is_achieved'
@then('something else we can check happens too')
def something_else_we_can_check_happens_too():
print 'something_else_we_can_check_happens_too'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment