9

How do I pass a parameter from a WHEN TO a THEN in pytest bdd?
For example, if I have the following code:

@when('<n1> is a number divisible by 10')
def n1_is_a_number_divisible_by_10(n1):
  assert (n1 % 10) == 0
  newN1 = n1/10
  return newN1

@then('the result will also be divisible by 3')
def the_result_will_also_be_divisible_by_3(newN1):
  assert newN1 % 3 == 0

How do I pass newN1 from the when to the then?

(I have tried making newN1 a global variable...this works but making things global is often frowned upon in python).

Mark
  • 1,337
  • 23
  • 34
theQuestionMan
  • 1,270
  • 2
  • 18
  • 29

2 Answers2

11

You can't pass anything from "when" to "then" by returning. Generally you want to avoid this situation. But if you have to, use a pytest fixture as a message box in both steps:

@pytest.fixture(scope='function')
def context():
    return {}

@when('<n1> is a number divisible by 10')
def n1_is_a_number_divisible_by_10(n1, context):
  assert (n1 % 10) == 0
  newN1 = n1 / 10
  context['partial_result'] = newN1

@then('the result will also be divisible by 3')
def the_result_will_also_be_divisible_by_3(context):
  assert context['partial_result'] % 3 == 0

Result of the "context" fixture is passed to the "when" step, populated, then passed to the "then" part. It isn't recreated each time.

As a side note, it's suboptimal to test your tests - you're doing so in the "when" part, asserting the divisibility. But this is just some sample code I guess.

Ctrl-C
  • 4,132
  • 1
  • 26
  • 29
3

In pytest-bdd version 4.1.0 the when step now supports target_fixture like the given step.

Here is an example from the pytest-bdd documentation

# test_blog.py

from pytest_bdd import scenarios, given, when, then

from my_app.models import Article

scenarios("blog.feature")


@given("there is an article", target_fixture="article")
def there_is_an_article():
    return Article()


@when("I request the "
"deletion of the article", target_fixture="request_result") # <--- here
def there_should_be_a_new_article(article, http_client):
    return http_client.delete(f"/articles/{article.uid}")


@then("the request should be successful")
def article_is_published(request_result):
    assert request_result.status_code == 200
Mark
  • 1,337
  • 23
  • 34