Skip to main content

TurลŸu

PyPI Doc Continuous Integration Coverage Report

This project allows you to write Gherkin-based behavior-driven development (BDD) tests and execute them using pytest.

It compiles Gherkin syntax into Python code using Abstract Syntax Tree (AST) manipulation, enabling seamless integration with pytest for running your tests.

Enjoy practicing BDD in modern Python (3.10+), type hinting, asyncio, dataclasses or Pydantic, pytest, playwright.

Features

  • Write tests using Gherkin syntax.
  • Write step definitions in Python for with type hinting to cast Gherkin parameters.
  • Execute tests directly with pytest.
  • Compile Gherkin scenarios to Python code using AST.

Getting started

Installation using uv

uv add --group dev tursu

Creating a new test suite

The simplest way to initialize a test suite is to run the TurลŸu cli.

uv run tursu init

Discover your tests.

๐ฟ uv run pytest --collect-only tests/functionals
========================== test session starts ==========================
platform linux -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
configfile: pyproject.toml
plugins: cov-6.0.0
collected 3 items

<Dir tursu>
  <Package tests>
    <Package funcs>
      <GherkinDocument login.feature>
        <Function test_7_Successful_sign_in_with_valid_credentials>
        <Function test_10_Sign_in_fails_with_wrong_password>
        <Function test_17_User_can_t_login_with_someone_else_username_16[Examples_16_0]>
        <Function test_17_User_can_t_login_with_someone_else_username_16[Examples_16_1]>

====================== 3 tests collected in 0.01s =======================

Run the tests.

All the suite

๐ฟ uv run pytest tests/functionals
========================== test session starts ==========================
platform linux -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
configfile: pyproject.toml
collected 3 items

tests/functionals/test_login.py ...                               [ 33%]
..                                                                [100%]

=========================== 3 passed in 0.02s ===========================

All the suite with details:

๐ฟ uv run pytest -v tests/functionals
============================= test session starts =============================
platform linux -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
configfile: pyproject.toml
collected 3 items

๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario: Successful sign-in with valid credentials
โœ… Given a set of users:
โœ… When Bob signs in with password dumbsecret
โœ… Then the user is connected with username Bob

๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario: Sign-in fails with wrong password
โœ… Given a set of users:
โœ… When Bob signs in with password notthat
โœ… Then the user is not connected

๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario Outline: User can\'t login with someone else username
โœ… Given a set of users:
โœ… When Bob signs in with password anothersecret
โœ… Then the user is not connected

๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario Outline: User can\'t login with someone else username
โœ… Given a set of users:
โœ… When Alice signs in with password dumbsecret
โœ… Then the user is not connected
                                                                         PASSED

============================== 3 passed in 0.02s ==============================

Choose your scenario file to test:

๐ฟ uv run pytest -vv tests/functionals/login.feature
========================== test session starts ==========================
platform linux -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
configfile: pyproject.toml
plugins: cov-6.0.0, tursu-0.11.1
collected 3 items

tests/functionals/login.feature::test_3_User_can_login <- test_login.py
๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario: Successful sign-in with valid credentials
โณ Given a user Bob with password dumbsecret
โœ… Given a user Bob with password dumbsecret
โณ When Bob signs in with password dumbsecret
โœ… When Bob signs in with password dumbsecret
โณ Then the user is connected with username Bob
โœ… Then the user is connected with username Bob
                                                            PASSED [ 33%]
tests/functionals/login.feature::test_7_User_can_t_login_with_wrong_password <- test_login.py
๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario: Sign-in fails with wrong password
โณ Given a user Bob with password dumbsecret
โœ… Given a user Bob with password dumbsecret
โณ When Bob signs in with password notthat
โœ… When Bob signs in with password notthat
โณ Then the user is not connected
โœ… Then the user is not connected
                                                            PASSED [ 66%]
tests/functionals/login.feature::test_12_User_can_t_login_with_someone_else_username <- test_login.py
๐Ÿ“„ Document: login.feature
๐Ÿฅ’ Feature: User signs in with the right password
๐ŸŽฌ Scenario: User can\'t login with someone else username
โณ Given a user Bob with password bobsecret
โœ… Given a user Bob with password bobsecret
โณ Given a user Alice with password alicesecret
โœ… Given a user Alice with password alicesecret
โณ When Alice signs in with password bobsecret
โœ… When Alice signs in with password bobsecret
โณ Then the user is not connected
โœ… Then the user is not connected

                                                            PASSED [100%]
=========================== 3 passed in 0.02s ===========================
You can choose the test name ( tests/tests2/login.feature::test_3_User_can_login )
or even decorate with tag and use pytest markers (`pytest -m <tag>`).

Get errors context

๐ฟ uv run pytest tests/functionals
========================== test session starts ===========================
platform linux -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
rootdir: /home/guillaume/workspace/git/tursu
configfile: pyproject.toml
plugins: cov-6.0.0, tursu-0.12.4, playwright-0.7.0, base-url-2.1.0
collected 3 items

tests/functionals/login.feature F..                                      [100%]

================================ FAILURES ================================
_________________________ test_3_User_can_login __________________________

self = <tursu.runner.TursuRunner object at 0x76103daadbe0>, step = 'Then'
text = 'the user is connected with username Bobby'
kwargs = {'app': <tests.functionals.conftest.DummyApp object at 0x76103daad940>}

    def run_step(
        self,
        step: StepKeyword,
        text: str,
        **kwargs: Any,
    ) -> None:
        try:
>           self.tursu.run_step(self, step, text, **kwargs)

src/tursu/runner.py:79:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/tursu/registry.py:102: in run_step
    handler(**matches)
src/tursu/steps.py:38: in __call__
    self.hook(**kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

app = <tests.functionals.conftest.DummyApp object at 0x76103daad940>
username = 'Bobby'

    @then("the user is connected with username {username}")
    def assert_connected(app: DummyApp, username: str):
>       assert app.connected_user == username
E       AssertionError

tests/functionals/steps.py:18: AssertionError

The above exception was the direct cause of the following exception:

request = <FixtureRequest for <Function test_3_User_can_login>>
capsys = <_pytest.capture.CaptureFixture object at 0x76103daae270>
tursu = <tursu.runtime.registry.Tursu object at 0x76103f107230>
app = <tests.functionals.conftest.DummyApp object at 0x76103daad940>

>   ???

test_login.py:12:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tursu.runner.TursuRunner object at 0x76103daadbe0>, step = 'Then'
text = 'the user is connected with username Bobby'
kwargs = {'app': <tests.functionals.conftest.DummyApp object at 0x76103daad940>}

    def run_step(
        self,
        step: StepKeyword,
        text: str,
        **kwargs: Any,
    ) -> None:
        try:
            self.tursu.run_step(self, step, text, **kwargs)
        except Exception as exc:
>           raise ScenarioFailed(self.fancy()) from exc
E           tursu.runtime.runner.ScenarioFailed:
E           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
E           โ”‚ ๐Ÿ“„ Document: login.feature                             โ”‚
E           โ”‚ ๐Ÿฅ’ Feature: User signs in with the right password      โ”‚
E           โ”‚ ๐ŸŽฌ Scenario: Successful sign-in with valid credentials โ”‚
E           โ”‚ โœ… Given a set of users:                               โ”‚
E           โ”‚ โœ… When Bob signs in with password dumbsecret          โ”‚
E           โ”‚ โŒ Then the user is connected with username Bobby      โ”‚
E           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

src/tursu/runner.py:81: ScenarioFailed
======================== short test summary info =========================
FAILED tests/functionals/login.feature::test_3_User_can_login - tursu.runner.ScenarioFailed:
If --trace is used, the tests files are written on the disk, and
the `???` in the context are replaced by the generated python test function.

This may be usefull in case of hard time debugging.

Great support of playwright.

Combining TurลŸu and pytest-playwright is a great experience. See the example in the documentation

Great support of asyncio.

TurลŸu can also be combined with pytest-playwright-asyncio and run tests has coroutine using pytest-asyncio.

Scenario can be decorated with a @asyncio tag. And they will run as a coroutine marked with @pytest.mark.asyncio.

And, the step definitions can be coroutine.

See the pytest-playwright-asyncio example in the documentation

Great support of pytest fixtures and faker.

See the example in the documentation

All Gherkin features are support.

TurลŸu use the gherkin-official package to parse Gherkin Scenario beeing compiled to python.

Metadata

Release files for tursu 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tursu 1.1.0
File Size Uploaded
tursu-1.1.0.tar.gz 32.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tursu 1.1.0
File Interpreter ABI Platform
tursu-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 67.8 kB

Release files / tursu-1.1.0.tar.gz

Download URL tursu-1.1.0.tar.gz
Size 32.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ff75d091c6e74794b7b5044f88efbdb7d5fcd8e3af154427114861eaea683b58
BLAKE2b-256 checksum
How to use checksums
3dadf34485e2946048c06907079abd270b236d580c87152e8d3b4296a6400e04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via pdm/2.26.6 CPython/3.13.12 Linux/6.14.0-1017-azure

Release files / tursu-1.1.0-py3-none-any.whl

Download URL tursu-1.1.0-py3-none-any.whl
Size 35.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
57e6a8c7aff0211edf6a69eda4ccd45b03b24e68bfa4d103b5b7e46da082e57b
BLAKE2b-256 checksum
How to use checksums
2d66a1dc272d6c9cb873b1caaef29b487b188472bce3fb51d1ebfbda9ae69b6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via pdm/2.26.6 CPython/3.13.12 Linux/6.14.0-1017-azure

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.17.1

2 release files

0.17.0

2 release files

0.16.3

2 release files

0.16.2

2 release files

0.16.1

2 release files

0.16.0

2 release files

0.15.2

2 release files

0.14.2

2 release files

0.14.1

2 release files

0.13.0

2 release files

0.12.5

2 release files

0.12.4

2 release files

0.12.3

2 release files

0.12.2

2 release files

0.12.1

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page