How to use pytest to confirm proper exception is raised

Question:

I have the following code to create an Object account. I raise an error if the account meets certain conditions, e.g. is too long. I want to use pytest to test that that functionality works.

class Account:

    def __init__(self, acct):

        self.tagged = {}
        self.untagged = {}
        self.acct_stats = {}

        try:
            if len(str(acct)) < 12:
                prepend_digit_range = 12 - len(str(acct))
                for i in range(prepend_digit_range):
                    acct = "0" + str(acct)
            if len(str(acct)) > 12:
                raise ValueError
        except ValueError:
            logging.error("Account ID " + str(acct) + " invalid")
            raise
        self.account_id = str(acct)

I’m trying to use pytest to test it.

First I tried this, which didn’t work:

# Per https://www.authentise.com/post/pytest-and-parametrization
@pytest.mark.skip("WIP")
@pytest.mark.parametrize(
    "account_id, expected",
    [
        pytest.mark.raises(
            (31415926535897932384626, "Account ID 31415926535897932384626 invalid"),
            exception=ValueError
        )
    ]
)
def test_account_setup_raise_error1(account_id, expected):
    account = Account(account_id)
    with expected:
        assert account.account_id == expected

Then I tried this:

# Per https://docs.pytest.org/en/stable/example/parametrize.html#parametrizing-conditional-raising
@pytest.mark.parametrize(
    "account_id, expected",
    [
        (
            (31415926535897932384626, "Account ID 31415926535897932384626 invalid"),
            ValueError,
        )
    ],
)
def test_account_setup_raise_error(account_id, expected):
    account = Account(account_id)
    with expected:
        assert account.account_id == expected

which doesn’t work either; I get this when I run pytest:

/usr/local/lib/python3.10/site-packages/pluggy/_hooks.py:265: in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
/usr/local/lib/python3.10/site-packages/pluggy/_manager.py:80: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
/usr/local/lib/python3.10/site-packages/_pytest/python.py:272: in pytest_pycollect_makeitem
    return list(collector._genfunctions(name, obj))
/usr/local/lib/python3.10/site-packages/_pytest/python.py:499: in _genfunctions
    self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc))
/usr/local/lib/python3.10/site-packages/pluggy/_hooks.py:292: in call_extra
    return self(**kwargs)
/usr/local/lib/python3.10/site-packages/pluggy/_hooks.py:265: in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
/usr/local/lib/python3.10/site-packages/pluggy/_manager.py:80: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
/usr/local/lib/python3.10/site-packages/_pytest/python.py:151: in pytest_generate_tests
    metafunc.parametrize(*marker.args, **marker.kwargs, _param_mark=marker)
/usr/local/lib/python3.10/site-packages/_pytest/python.py:1300: in parametrize
    argnames, parametersets = ParameterSet._for_parametrize(
/usr/local/lib/python3.10/site-packages/_pytest/mark/structures.py:166: in _for_parametrize
    if len(param.values) != len(argnames):
E   TypeError: object of type 'MarkDecorator' has no len()

Any thoughts on why? How can I get a test to work that tests that the proper exception is raised?

UPDATE: I’ve implemented @pl3b’s response and got the test code working. It is below; I’ve updated the parameters to match the changes.


@pytest.mark.parametrize(
    "account_id",
    [
        (
            (31415926535897932384626),
            ("blah"),
            ValueError,
        )
    ],
)
def test_account_setup_raise_error(account_id):
    with pytest.raises(ValueError, match="invalid"):
        account = Account(account_id)
        print(account)

Note that I also added another test case, for which I updated the code itself:

            if len(str(acct)) > 12 or re.match("^[0-9]+$", str(acct)) is None:
                raise ValueError("Account ID " + str(acct) + " invalid")
Asked By: Burvil

||

Answers:

Have you tried with pytest.raises()?

with pytest.raises(ValueError, match='invalid'):
    account = Account(account_id)

Source

Answered By: pL3b
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.