Asserting Exceptions with Pytest

Kinyanjui Wangonya on January 29, 2019

First time I had someone review my pull requests, she was pretty strict on tests. I couldn't merge if the tests were failing, of course. But I also... [Read Full]
markdown guide

I know it's just an example but I think I should mention it for beginners: there are not many cases when raising Exception is the best strategy. The reason being that Exception is the class from which most error classes inherit from.

>>> Exception.__mro__
(<class 'Exception'>, <class 'BaseException'>, <class 'object'>)
>>> ValueError.__mro__
(<class 'ValueError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)

It would make it harder for the caller to properly handle different types of exceptions.

In your case ValueError (or a custom exception) is probably more appropriate:

Raised when an operation or function receives an argument that has the right type but an inappropriate value

A bonus tip: pytest.raises accepts an argument that you might find useful: match. You could rewrite:

 with pytest.raises(Exception) as e:
        assert check_email_format("bademail.com")
    assert str(e) == "Invalid email format"


with pytest.raises(Exception, match="Invalid email format"):
        assert check_email_format("bademail.com")

match is used to check the error message with a regular expression.

Hope this helps!


I just wanted to correct a common mistake in this comment since it was one of the first results from my google search. message is actually used for setting the message that pytest.rasies will display on failure. It's not about a comparison to the exception's message. match should always be used for that purpose. docs.pytest.org/en/latest/referenc...

(This problem catches almost everyone at one point or another. Which is the reason that pytest has chosen to deprecate the message parameter ;-)


thank you Toshio! I'll update the comment!

What did you search on Google to get here?


Yeah, it helps! Thanks for the input. It was just an example, of course in an ideal situation things would be different. I should have mentioned that.

Thanks again!


Hi have tried the same solution but still having the problem.

def get_param(param)

if param is None:
raise ValueError('param is not set')

def test_param():
with pytest.raises(ValueError) as e:

The problem is that when function does not raise exception, test_param() gets fail with the following error.

It works as expected when get_param(param) function throws exception.

Thanks in advance :-)


That's the expected behaviour. The test is checking that an exception was raised, so if that doesn't happen, the tests fails.


What does this mean?
"But I also couldn't merge if coverage had decreased by even 1%.".
Would you please explain it a bit more?

code of conduct - report abuse