0

I'm wondering if there's a way to define step test functions inside Python class with pytest-bdd framework.

Let me elaborate a bit further..., suppose that we have a feature file like this:

"test.feature" file:

Feature: Transaction
    Calculate the leftover money at the end of a transaction

    Scenario Outline: Withdraw Money
        Given I deposit <initial_amount>
        When I withdraw <withdrawn_amount>
        Then I should only have <leftover_money> left

        Examples:
            | initial_amount | withdrawn_amount | leftover_money |
            | $100           | $30              | $70            |
            | $1000          | $50              | $950           |
            | $3000          | $200             | $2800          |

and then we have the step functions written like this:

"test_transaction.py" file:

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

def pytest_configure():
    pytest.AMT = 0

class TestWithdrawal:
    @scenario('test.feature', 'Withdraw Money')
    def test_withdraw():
        pass

    @given(
        parsers.cfparse(
            "I deposit ${amount:Number}",
            extra_types={"Number": int}
        ),
        target_fixture="initial_amount"
    )
    def initial_amount(amount):
        return amount

    @when(
        parsers.cfparse(
            "I withdraw ${withdrawn_amount:Number}",
            extra_types={"Number": int}
        )
    )
    def withdraw_money(initial_amount, withdrawn_amount):
        pytest.AMT = initial_amount - withdrawn_amount

    @then(
        parsers.cfparse(
            "I should only have ${leftover_amount:Number} left",
            extra_types={"Number": int}
        )
    )
    def leftover_money(leftover_amount):
        assert pytest.AMT == leftover_amount

When I tried to run the test with this command from my terminal:

pytest test_transaction.py

I get this error below:

=================================================================================================== ERRORS ====================================================================================================
_______________________________________________________________________________ ERROR collecting test_transaction_with_class.py _______________________________________________________________________________
invalid method signature

During handling of the above exception, another exception occurred:
Could not determine arguments of <bound method step.<locals>.decorator.<locals>.step_function_marker of <test_transaction_with_class.TestWithdrawal object at 0x1071aa550>>: invalid method signature
=========================================================================================== short test summary info ===========================================================================================
ERROR test_transaction_with_class.py::TestWithdrawal
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================================================================================== 1 error in 0.06s ===============================================================================================

which I think means that pytest-bdd framework doesn't support grouping a set of tests inside a class.

if this is true..., this is almost a deal breaker for me as we can easily group a set of tests inside a class with pytest.

blue2609
  • 841
  • 2
  • 10
  • 25
  • 1
    The method signature is invalid as your instance methods are not referencing `self`, for example: `def test_withdraw(self):`, this applies to all instance methods for Python classes. Why do you need them in classes in the first place? – kykyi Mar 08 '23 at 07:36
  • Hi @kykyi - thanks for the reply! Unfortunately even after following your suggestion and adding `self` as the first argument to these methods, I still got the exact same error message. As to the reason why I would like to use a class, it's because you can create class attributes or instance attributes that like "total amount" for example in this case. This "total amount" can then be passed around between class/instance methods to modify its value. Would also make it easier to construct the tests because I'm used to think in an Object Oriented Programming way. – blue2609 Mar 08 '23 at 11:02
  • Have you tried using `pytest.fixture` for this? `pytest-bdd`'s given/when/then decorators can be used as fixtures when using the `target_fixture` param. Link to docs: https://docs.pytest.org/en/6.2.x/fixture.html – kykyi Mar 08 '23 at 11:41
  • @kykyi, yeah I did, I tried using the `target_fixture` parameter and it does work :). But then again there doesn't seem to be any way to group these tests together in a class. It is what it is, I suppose there are pros and cons to using this `pytest-bdd` package. Can I ask you something @kykyi? how do you generate an automated report of test results after running these test cases? I'm trying to explore Allure test reporting web server to generate an automated reporting of these test results. – blue2609 Mar 08 '23 at 11:45
  • Unfortunately I'm a bit out of my depth there! I just use `pytest` and `pytest-bdd` in our CI so no need to report as such – kykyi Mar 08 '23 at 11:47
  • 1
    @kykyi Oh mate please don't say that! Dude I'm literally just starting using these things as well! . Yeah I have the same idea, integrate pytest and pytest-bdd with a CI system. Thanks so much for answering all of my messages! – blue2609 Mar 08 '23 at 11:49

0 Answers0