# 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. ```bash # 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: ```bash 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. ```bash touch tests/functionals/__init__.py ``` - create a minimal conftest.py ```bash 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 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 ```python 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 ```python 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 ```python 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](#pattern-matcher) for help. ``` ### tursu ```python 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 ```bash uv run pytest --trace -sxv tests/functionals/ ```