pytest fixture not found (pytest-bdd)

5.6k views Asked by At

I have the following step definitions, which result in an error because the @given fixture is not found, even though it is defined in target_fixture:

import pytest
from pytest_bdd import scenario, given, when, then, parsers
from admin import Admin

@scenario('../features/Admin.feature',
          'register a new user')

def test_admin():
    pass

@given('I\'m logged in as an admin at <host_name> with email <admin_email> and password <admin_password>', target_fixture="admin_login")
def admin_login(host_name, admin_email, admin_password):
    admin = Admin(admin_email, admin_password)
    admin.login(host_name)
#    assert admin.status_code == 200
    return admin

@when('I call the register method for host <host_name> with email <user_email> and password <user_password> and firstName <first_name> and last name <last_name>')
def test_register(admin_login, host_name, user_email, first_name, last_name):
    admin_login.register(host_name, user_email, first_name, last_name)
    assert admin_login.status_code == 200

@then('the user will be able to log in to <host_name> with email <user_email> and password <user_password>')
def test_login(admin_login):
    print(admin_login)
    assert 3 == 3

This results in the error:

platform darwin -- Python 3.8.5, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /Users/davidjoseph/work/
plugins: bdd-4.0.1
collected 3 items                                                                                                                                       

tests/step_defs/test_admin.py EEF                                                                                                                 [100%]

======================================================================== ERRORS =========================================================================
____________________________________________________________ ERROR at setup of test_register ____________________________________________________________
file /Users/davidjoseph/work/tests/step_defs/test_admin.py, line 18
  @when('I call the register method for host <host_name> with email <user_email> and password <user_password> and firstName <first_name> and last name <last_name>')
  def test_register(admin_login, host_name, user_email, first_name, last_name):
E       fixture 'admin_login' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestbdd_given_I'm logged in as an admin at <host_name> with email <admin_email> and password <admin_password>, pytestbdd_given_trace, pytestbdd_then_the user will be able to log in to <host_name> with email <user_email> and password <user_password>, pytestbdd_then_trace, pytestbdd_when_I call the register method for host <host_name> with email <user_email> and password <user_password> and firstName <first_name> and last name <last_name>, pytestbdd_when_trace, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

Can anyone tell me why admin_login is being recognized as a fixture?

2

There are 2 answers

3
hoefling On BEST ANSWER

Either downgrade to pytest-bdd<4 where this behaviour is still accepted, or rename the steps by removing the test_ prefix to prevent pytest from recognizing them as separate tests.

@when(...)
def register(admin_login, ...):
    ...

@then(...)
def login(admin_login):
    ...

should work.

0
JBT On

The name or prefix of a Gherkin step function does not matter: all scenario parts are turned into fixtures "under the hood" in pytest-bdd with a special form of name mangling. This cannot be stopped, as far as I know, and is one of a long list of problems and massive overcomplications with BDD and the associated tools that has set the QA discipline back maybe a decade.

But if you're forced to use BDD (school assignment, etc), just mark any Gherkin step function as a regular pytest fixture, too, and you can pass it as a fixture in the manner you expect (via the name of function, without invoking parentheses), even when using the pytest-bdd framework:

"""

@pytest.fixture
@given('I\'m logged in as an admin at <host_name> with email <admin_email> and password <admin_password>') # Remove """target_fixture""" arg
def admin_login(host_name, admin_email, admin_password):

    ...

"""