0

I'm very confused. I'm trying to learn to use pytest-bdd and gherkin, but I'm getting a TypeError saying NoneType is not iterable. I assume this means that the dict I'm trying to get values from is somehow becoming a NoneType object somewhere in here, but I have no idea when, how, or why. What's happening? How can I fix this code? (Please assume that the program this code is referencing works as intended, because it does.)

This is the error I'm getting a bunch of times (once for each test case):

________________________ test_verify_correct_returns_for_retirement_time[2021-11-January-2099] ________________________

request = <FixtureRequest for <Function test_verify_correct_returns_for_retirement_time[2021-11-January-2099]>>
_pytest_bdd_example = {'month': '11', 'month_name': 'January', 'retire_year': '2099', 'year': '2021'}

    @pytest.mark.usefixtures(*args)
    def scenario_wrapper(request, _pytest_bdd_example):
        scenario = templated_scenario.render(_pytest_bdd_example)
>       _execute_scenario(feature, scenario, request)

..\..\..\..\appdata\local\programs\python\python39\lib\site-packages\pytest_bdd\scenario.py:174:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\..\..\appdata\local\programs\python\python39\lib\site-packages\pytest_bdd\scenario.py:144: in _execute_scenario
    _execute_step_function(request, scenario, step, step_func)
..\..\..\..\appdata\local\programs\python\python39\lib\site-packages\pytest_bdd\scenario.py:114: in _execute_step_function
    return_value = step_func(**kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

user_inputs = {'user_birthmonth': '11', 'user_birthyear': '2021'}, retire_year = '2099', month_name = 'January'

    @then(parsers.parse("the text the program returns should include 'This will be in {month_name} of {retire_year}.'"), converters=CONVERTERS)
    def check_return(user_inputs, retire_year, month_name):
>       assert f'This will be in {month_name} of {retire_year}.' in main(user_inputs["user_birthyear"], user_inputs["user_birthmonth"])
E       TypeError: argument of type 'NoneType' is not iterable

test_basic_functionality_steps.py:36: TypeError
from pytest_bdd import scenarios, parsers, given, when, then
import pytest
from .full_retirement_age import main

CONVERTERS = {
    'year': str,
    'month': str,
    'retire_years': str,
    'retire_months': str,
    'retire_year': str,
    'month_name': str
}

scenarios("basic_functionality.feature")

@pytest.fixture
@given("the user is using the full_retirement_age.py program")
def user_inputs():
    return dict(user_birthyear="", user_birthmonth="")

@when(parsers.parse('the user enters {year} when prompted for their year of birth'), converters=CONVERTERS)
def input_year(user_inputs, year):
    user_inputs["user_birthyear"] = year

@when(parsers.parse('the user enters {month} when prompted for their month of birth'), converters=CONVERTERS)
def input_month(user_inputs, month):
    user_inputs["user_birthmonth"] = month


@then(parsers.parse("the text the program returns should include 'Your full retirement age is {retire_years} and {retire_months} months.'"), converters=CONVERTERS)
def check_return(user_inputs, retire_years, retire_months):
    assert f'Your full retirement age is {retire_years} and {retire_months} months.' in main(user_inputs["user_birthyear"], user_inputs["user_birthmonth"])

@then(parsers.parse("the text the program returns should include 'This will be in {month_name} of {retire_year}.'"), converters=CONVERTERS)
def check_return(user_inputs, retire_year, month_name):
    assert f'This will be in {month_name} of {retire_year}.' in main(user_inputs["user_birthyear"], user_inputs["user_birthmonth"])
Feature: Shows Retirement Age and Time
  A user will be able to enter their birth year and month,
  and get back a string of text printed to the console
  that tells them their retirement age as well as the
  year and month that they will retire


  Scenario Outline: Verify Correct Returns for Retirement Age
    Given the user is using the full_retirement_age.py program
    When the user enters <year> when prompted for their year of birth
    And the user enters <month> when prompted for their month of birth
    Then the text the program returns should include 'Your full retirement age is <retire_years> and <retire_months> months.'
    
    # month should not effect the output of retirement age (but should for retirement time)
    Examples:
      | year | month | retire_years | retire_months |
      | 1943 | 7     | 66           | 0             |
      | 1954 | 12    | 66           | 0             |
      | 1942 | 6     | 65           | 10            |
      | 1920 | 4     | 62           | 2             |
      | 1900 | 8     | 58           | 10            |
      | 1955 | 9     | 66           | 2             |
      | 1980 | 1     | 70           | 4             |
      | 2021 | 11    | 77           | 2             |
    
  Scenario Outline: Verify Correct Returns for Retirement Time
    Given the user is using the full_retirement_age.py program
    When the user enters <year> when prompted for their year of birth
    And the user enters <month> when prompted for their month of birth
    Then the text the program returns should include 'This will be in <month_name> of <retire_year>.'
    
    # In order for these examples to return the correct date, the last scenario
    # must work in its entirety as this scenario depends on the function the
    # last scenario was testing
    Examples:
      | year | month | month_name | retire_year |
      | 1943 | 7     | July       | 2009        |
      | 1954 | 12    | December   | 2020        |
      | 1942 | 6     | April      | 2008        |
      | 1920 | 4     | June       | 1982        |
      | 1900 | 8     | June       | 1959        |
      | 1955 | 9     | November   | 2021        |
      | 1980 | 1     | May        | 2050        |
      | 2021 | 11    | January    | 2099        |
Ben
  • 82
  • 11
  • 1
    ". I assume this means that the dict I'm trying to get values from is somehow becoming a NoneType object somewhere in here" No; it means that the `main` function you are `import`ing is supposed to return a string, but it returns `None` instead. You can tell this by looking at the line of code that it complains about, and how the complaint is phrased. `not iterable` means that it needed something it can iterate over. It needs that because your `assert` condition uses `in`. `of type 'NoneType'` means `None`, since `None` is the only object of that type. – Karl Knechtel Nov 20 '21 at 14:56
  • 1
    Anyway, we can't possibly tell you what is wrong with the code that you're testing (beyond the *symptoms*, at least), from you showing us the code that you use to do the tests. Please read https://stackoverflow.com/help/minimal-reproducible-example. – Karl Knechtel Nov 20 '21 at 14:58
  • 1
    My god. Every time its always the stupidest mistakes. I was printing instead of returning what I needed to. This is what you learn on day one of python. I'm so sorry for wasting your time. But I really appreciate what you've done. I've been looking at this code aimlessly for quite a while now. Thank you so much – Ben Nov 20 '21 at 15:02

0 Answers0