Migrate from pytest-bdd¶
pytest-bdd is an alternative to behave that works with pytest.
It’s quite similar to tursu in the idea, it is more mature, but its also more verbose and the approach is different.
pytest-bdd does not compile to AST, so while using pdb, it’s harder to navigate and now in which step the scenario is currently. In case of failure, the context provided by pytest-bdd is minimal.
Also note that in tursu, you can provide the scenario file in the cli command
as a test, not a test_*.py
file.
# using pytest-bdd
uv run pytest --trace -sxv tests/functionals/test_scenario_binding_file.py
# using tursu
uv run pytest --trace -sxv tests/functionals/my_gherkin.scenario
Step 1 - Install tursu and configure it.¶
Installation:
uv add --group dev tursu
Add the Tursu Gherkin compiler to AST generate the tests suite:
Ensure the
__init__.py
file exists in the functionals tests suite.
touch tests/functionals/__init__.py
create a minimal conftest.py
cat << 'EOF' > tests/functionals/conftest.py
from tursu.plugin import tursu_collect_file
tursu_collect_file()
EOF
remove all the scenario/scenarios call of pytest_bdd
diff --git a/tests/test_login.py b/tests/test_login.py
index c373bd4..63c4b46 100644
--- a/tests/test_login.py
+++ b/tests/test_login.py
@@ -1,4 +1,4 @@
-from pytest_bdd import scenarios, given, when, then, parsers
+from pytest_bdd import given, when, then, parsers
from .conftest import DummyApp
@@ -27,6 +27,3 @@ def assert_connected(app: DummyApp, username: str):
@then(parsers.parse("I am not connected"))
def assert_not_connected(app: DummyApp):
assert app.connected_user is None
-
-
-scenarios("scenario")
Step 2¶
In pytest-bdd, the given function create the fixtures, where in tursu,
you create the fixture, given step manipulate it.
Futhermore, remove parsers.parse, use plain string.
pytest-bdd¶
from pytest_bdd import given, parsers
@given(
parsers.parse("a user {username} with password {password}"),
target_fixture="app",
)
def give_user(username: str, password: str) -> DummyApp:
app = DummyApp()
app.users[username] = password
return app
tursu¶
from tursu import given
@pytest.fixture()
def app() -> DummyApp:
return DummyApp()
@given("a user {username} with password {password}")
def give_user(app: DummyApp, username: str, password: str):
app.users[username] = password
Step 3 - cleanup all the when and then decorators¶
pytest-bdd¶
from pytest_bdd import given, when, then, parsers
@when(parsers.parse("{username} login with password {password}"))
def login(app: DummyApp, username: str, password: str):
app.login(username, password)
@then(parsers.parse("I am connected with username {username}"))
def assert_connected(app: DummyApp, username: str):
assert app.connected_user == username
Note
If you are using extra_types, remove it too, tursu matcher uses python type hinting,
refer to the pattern matcher documentation for help.
tursu¶
from tursu import then, when
@when("{username} login with password {password}")
def login(app: DummyApp, username: str, password: str):
app.login(username, password)
@then("I am connected with username {username}")
def assert_connected(app: DummyApp, username: str):
assert app.connected_user == username
Step 4 - clean the names¶
Remove all the test_
prefix of the steps file, test_
file are entirely
generated by tursu before runing the tests, and cleaned up at the end.
You can arrange all your steps
in your testing directory by the way.
Step 5 - Run the test, enable tracing!¶
It’s hard to run a debugger in behave, remote debugging is mandatory, in pytest, you can use start a debugger in your test by a
uv run pytest --trace -sxv tests/functionals/