forked from test_framework/pytest-bdd
587 lines
15 KiB
Python
587 lines
15 KiB
Python
import textwrap
|
|
|
|
|
|
def test_steps(pytester):
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps are executed one by one
|
|
Steps are executed one by one. Given and When sections
|
|
are not mandatory in some cases.
|
|
|
|
Scenario: Executed step by step
|
|
Given I have a foo fixture with value "foo"
|
|
And there is a list
|
|
When I append 1 to the list
|
|
And I append 2 to the list
|
|
And I append 3 to the list
|
|
Then foo should have value "foo"
|
|
But the list should be [1, 2, 3]
|
|
"""
|
|
),
|
|
)
|
|
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import given, when, then, scenario
|
|
|
|
@scenario("steps.feature", "Executed step by step")
|
|
def test_steps():
|
|
pass
|
|
|
|
@given('I have a foo fixture with value "foo"', target_fixture="foo")
|
|
def _():
|
|
return "foo"
|
|
|
|
|
|
@given("there is a list", target_fixture="results")
|
|
def _():
|
|
return []
|
|
|
|
|
|
@when("I append 1 to the list")
|
|
def _(results):
|
|
results.append(1)
|
|
|
|
|
|
@when("I append 2 to the list")
|
|
def _(results):
|
|
results.append(2)
|
|
|
|
|
|
@when("I append 3 to the list")
|
|
def _(results):
|
|
results.append(3)
|
|
|
|
|
|
@then('foo should have value "foo"')
|
|
def _(foo):
|
|
assert foo == "foo"
|
|
|
|
|
|
@then("the list should be [1, 2, 3]")
|
|
def _(results):
|
|
assert results == [1, 2, 3]
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_step_function_can_be_decorated_multiple_times(pytester):
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps decoration
|
|
|
|
Scenario: Step function can be decorated multiple times
|
|
Given there is a foo with value 42
|
|
And there is a second foo with value 43
|
|
When I do nothing
|
|
And I do nothing again
|
|
Then I make no mistakes
|
|
And I make no mistakes again
|
|
|
|
"""
|
|
),
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import given, when, then, scenario, parsers
|
|
|
|
@scenario("steps.feature", "Step function can be decorated multiple times")
|
|
def test_steps():
|
|
pass
|
|
|
|
|
|
@given(parsers.parse("there is a foo with value {value}"), target_fixture="foo")
|
|
@given(parsers.parse("there is a second foo with value {value}"), target_fixture="second_foo")
|
|
def _(value):
|
|
return value
|
|
|
|
|
|
@when("I do nothing")
|
|
@when("I do nothing again")
|
|
def _():
|
|
pass
|
|
|
|
|
|
@then("I make no mistakes")
|
|
@then("I make no mistakes again")
|
|
def _():
|
|
assert True
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_all_steps_can_provide_fixtures(pytester):
|
|
"""Test that given/when/then can all provide fixtures."""
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Step fixture
|
|
Scenario: Given steps can provide fixture
|
|
Given Foo is "bar"
|
|
Then foo should be "bar"
|
|
Scenario: When steps can provide fixture
|
|
When Foo is "baz"
|
|
Then foo should be "baz"
|
|
Scenario: Then steps can provide fixture
|
|
Then foo is "qux"
|
|
And foo should be "qux"
|
|
"""
|
|
),
|
|
)
|
|
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import given, when, then, parsers, scenarios
|
|
|
|
scenarios("steps.feature")
|
|
|
|
@given(parsers.parse('Foo is "{value}"'), target_fixture="foo")
|
|
def _(value):
|
|
return value
|
|
|
|
|
|
@when(parsers.parse('Foo is "{value}"'), target_fixture="foo")
|
|
def _(value):
|
|
return value
|
|
|
|
|
|
@then(parsers.parse('Foo is "{value}"'), target_fixture="foo")
|
|
def _(value):
|
|
return value
|
|
|
|
|
|
@then(parsers.parse('foo should be "{value}"'))
|
|
def _(foo, value):
|
|
assert foo == value
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=3, failed=0)
|
|
|
|
|
|
def test_when_first(pytester):
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps are executed one by one
|
|
Steps are executed one by one. Given and When sections
|
|
are not mandatory in some cases.
|
|
|
|
Scenario: When step can be the first
|
|
When I do nothing
|
|
Then I make no mistakes
|
|
"""
|
|
),
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import when, then, scenario
|
|
|
|
@scenario("steps.feature", "When step can be the first")
|
|
def test_steps():
|
|
pass
|
|
|
|
@when("I do nothing")
|
|
def _():
|
|
pass
|
|
|
|
|
|
@then("I make no mistakes")
|
|
def _():
|
|
assert True
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_then_after_given(pytester):
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps are executed one by one
|
|
Steps are executed one by one. Given and When sections
|
|
are not mandatory in some cases.
|
|
|
|
Scenario: Then step can follow Given step
|
|
Given I have a foo fixture with value "foo"
|
|
Then foo should have value "foo"
|
|
|
|
"""
|
|
),
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import given, then, scenario
|
|
|
|
@scenario("steps.feature", "Then step can follow Given step")
|
|
def test_steps():
|
|
pass
|
|
|
|
@given('I have a foo fixture with value "foo"', target_fixture="foo")
|
|
def _():
|
|
return "foo"
|
|
|
|
@then('foo should have value "foo"')
|
|
def _(foo):
|
|
assert foo == "foo"
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_conftest(pytester):
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps are executed one by one
|
|
Steps are executed one by one. Given and When sections
|
|
are not mandatory in some cases.
|
|
|
|
Scenario: All steps are declared in the conftest
|
|
Given I have a bar
|
|
Then bar should have value "bar"
|
|
|
|
"""
|
|
),
|
|
)
|
|
pytester.makeconftest(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import given, then
|
|
|
|
|
|
@given("I have a bar", target_fixture="bar")
|
|
def _():
|
|
return "bar"
|
|
|
|
|
|
@then('bar should have value "bar"')
|
|
def _(bar):
|
|
assert bar == "bar"
|
|
|
|
"""
|
|
)
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import scenario
|
|
|
|
@scenario("steps.feature", "All steps are declared in the conftest")
|
|
def test_steps():
|
|
pass
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_multiple_given(pytester):
|
|
"""Using the same given fixture raises an error."""
|
|
pytester.makefile(
|
|
".feature",
|
|
steps=textwrap.dedent(
|
|
"""\
|
|
Feature: Steps are executed one by one
|
|
Scenario: Using the same given twice
|
|
Given foo is "foo"
|
|
And foo is "bar"
|
|
Then foo should be "bar"
|
|
|
|
"""
|
|
),
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
from pytest_bdd import parsers, given, then, scenario
|
|
|
|
|
|
@given(parsers.parse("foo is {value}"), target_fixture="foo")
|
|
def _(value):
|
|
return value
|
|
|
|
|
|
@then(parsers.parse("foo should be {value}"))
|
|
def _(foo, value):
|
|
assert foo == value
|
|
|
|
|
|
@scenario("steps.feature", "Using the same given twice")
|
|
def test_given_twice():
|
|
pass
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest()
|
|
result.assert_outcomes(passed=1, failed=0)
|
|
|
|
|
|
def test_step_hooks(pytester):
|
|
"""When step fails."""
|
|
pytester.makefile(
|
|
".feature",
|
|
test="""
|
|
Scenario: When step has hook on failure
|
|
Given I have a bar
|
|
When it fails
|
|
|
|
Scenario: When step's dependency a has failure
|
|
Given I have a bar
|
|
When it's dependency fails
|
|
|
|
Scenario: When step is not found
|
|
Given not found
|
|
|
|
Scenario: When step validation error happens
|
|
Given foo
|
|
And foo
|
|
""",
|
|
)
|
|
pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
from pytest_bdd import given, when, scenario
|
|
|
|
@given('I have a bar')
|
|
def _():
|
|
return 'bar'
|
|
|
|
@when('it fails')
|
|
def _():
|
|
raise Exception('when fails')
|
|
|
|
@given('I have a bar')
|
|
def _():
|
|
return 'bar'
|
|
|
|
@pytest.fixture
|
|
def dependency():
|
|
raise Exception('dependency fails')
|
|
|
|
@when("it's dependency fails")
|
|
def _(dependency):
|
|
pass
|
|
|
|
@scenario('test.feature', "When step's dependency a has failure")
|
|
def test_when_dependency_fails():
|
|
pass
|
|
|
|
@scenario('test.feature', 'When step has hook on failure')
|
|
def test_when_fails():
|
|
pass
|
|
|
|
@scenario('test.feature', 'When step is not found')
|
|
def test_when_not_found():
|
|
pass
|
|
|
|
@when('foo')
|
|
def _():
|
|
return 'foo'
|
|
|
|
@scenario('test.feature', 'When step validation error happens')
|
|
def test_when_step_validation_error():
|
|
pass
|
|
"""
|
|
)
|
|
reprec = pytester.inline_run("-k test_when_fails")
|
|
reprec.assertoutcome(failed=1)
|
|
|
|
calls = reprec.getcalls("pytest_bdd_before_scenario")
|
|
assert calls[0].request
|
|
|
|
calls = reprec.getcalls("pytest_bdd_after_scenario")
|
|
assert calls[0].request
|
|
|
|
calls = reprec.getcalls("pytest_bdd_before_step")
|
|
assert calls[0].request
|
|
|
|
calls = reprec.getcalls("pytest_bdd_before_step_call")
|
|
assert calls[0].request
|
|
|
|
calls = reprec.getcalls("pytest_bdd_after_step")
|
|
assert calls[0].request
|
|
|
|
calls = reprec.getcalls("pytest_bdd_step_error")
|
|
assert calls[0].request
|
|
|
|
reprec = pytester.inline_run("-k test_when_not_found")
|
|
reprec.assertoutcome(failed=1)
|
|
|
|
calls = reprec.getcalls("pytest_bdd_step_func_lookup_error")
|
|
assert calls[0].request
|
|
|
|
reprec = pytester.inline_run("-k test_when_step_validation_error")
|
|
reprec.assertoutcome(failed=1)
|
|
|
|
reprec = pytester.inline_run("-k test_when_dependency_fails", "-vv")
|
|
reprec.assertoutcome(failed=1)
|
|
|
|
calls = reprec.getcalls("pytest_bdd_before_step")
|
|
assert len(calls) == 2
|
|
|
|
calls = reprec.getcalls("pytest_bdd_before_step_call")
|
|
assert len(calls) == 1
|
|
|
|
calls = reprec.getcalls("pytest_bdd_step_error")
|
|
assert calls[0].request
|
|
|
|
|
|
def test_step_trace(pytester):
|
|
"""Test step trace."""
|
|
pytester.makeini(
|
|
"""
|
|
[pytest]
|
|
console_output_style=classic
|
|
"""
|
|
)
|
|
|
|
pytester.makefile(
|
|
".feature",
|
|
test="""
|
|
Scenario: When step has failure
|
|
Given I have a bar
|
|
When it fails
|
|
|
|
Scenario: When step is not found
|
|
Given not found
|
|
|
|
Scenario: When step validation error happens
|
|
Given foo
|
|
And foo
|
|
""",
|
|
)
|
|
pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
from pytest_bdd import given, when, scenario
|
|
|
|
@given('I have a bar')
|
|
def _():
|
|
return 'bar'
|
|
|
|
@when('it fails')
|
|
def _():
|
|
raise Exception('when fails')
|
|
|
|
@scenario('test.feature', 'When step has failure')
|
|
def test_when_fails_inline():
|
|
pass
|
|
|
|
@scenario('test.feature', 'When step has failure')
|
|
def test_when_fails_decorated():
|
|
pass
|
|
|
|
@scenario('test.feature', 'When step is not found')
|
|
def test_when_not_found():
|
|
pass
|
|
|
|
@when('foo')
|
|
def _():
|
|
return 'foo'
|
|
|
|
@scenario('test.feature', 'When step validation error happens')
|
|
def test_when_step_validation_error():
|
|
pass
|
|
"""
|
|
)
|
|
result = pytester.runpytest("-k test_when_fails_inline", "-vv")
|
|
result.assert_outcomes(failed=1)
|
|
result.stdout.fnmatch_lines(["*test_when_fails_inline*FAILED"])
|
|
assert "INTERNALERROR" not in result.stdout.str()
|
|
|
|
result = pytester.runpytest("-k test_when_fails_decorated", "-vv")
|
|
result.assert_outcomes(failed=1)
|
|
result.stdout.fnmatch_lines(["*test_when_fails_decorated*FAILED"])
|
|
assert "INTERNALERROR" not in result.stdout.str()
|
|
|
|
result = pytester.runpytest("-k test_when_not_found", "-vv")
|
|
result.assert_outcomes(failed=1)
|
|
result.stdout.fnmatch_lines(["*test_when_not_found*FAILED"])
|
|
assert "INTERNALERROR" not in result.stdout.str()
|
|
|
|
result = pytester.runpytest("-k test_when_step_validation_error", "-vv")
|
|
result.assert_outcomes(failed=1)
|
|
result.stdout.fnmatch_lines(["*test_when_step_validation_error*FAILED"])
|
|
assert "INTERNALERROR" not in result.stdout.str()
|
|
|
|
|
|
def test_steps_with_yield(pytester):
|
|
"""Test that steps definition containing a yield statement work the same way as
|
|
pytest fixture do, that is the code after the yield is executed during teardown."""
|
|
|
|
pytester.makefile(
|
|
".feature",
|
|
a="""\
|
|
Feature: A feature
|
|
|
|
Scenario: A scenario
|
|
When I setup stuff
|
|
Then stuff should be 42
|
|
""",
|
|
)
|
|
pytester.makepyfile(
|
|
textwrap.dedent(
|
|
"""\
|
|
import pytest
|
|
from pytest_bdd import given, when, then, scenarios
|
|
|
|
scenarios("a.feature")
|
|
|
|
@when("I setup stuff", target_fixture="stuff")
|
|
def _():
|
|
print("Setting up...")
|
|
yield 42
|
|
print("Tearing down...")
|
|
|
|
|
|
@then("stuff should be 42")
|
|
def _(stuff):
|
|
assert stuff == 42
|
|
print("Asserted stuff is 42")
|
|
|
|
"""
|
|
)
|
|
)
|
|
result = pytester.runpytest("-s")
|
|
result.assert_outcomes(passed=1)
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"*Setting up...*",
|
|
"*Asserted stuff is 42*",
|
|
"*Tearing down...*",
|
|
]
|
|
)
|