Skip to main content

Functions That Raise Exceptions

A Python function that is handed bad input should say so by raising an exception: on success it returns its result, on failure it raises an error — such as ValueError — that explains what went wrong.

A test for such a function must check both paths: good input returns the right value and raises nothing, and bad input really does raise — a function that silently accepts bad input is a bug too.

pytest.raises is the tool for the bad path: a with block that fails the test unless the expected exception comes out of it.


The Good Path

For a valid input there is nothing extra to write. Call the function, then compare the value. If the call raises instead, the exception ends the test by itself and the report shows it — you do not have to check for it first.

Valid input, no exception

safe_divide(10, 2) must return 5 and must not raise. The call comes first; an unexpected exception would end the test right there. Only then is the value compared.

Prompt
Write a Python test file with a safe_divide function that raises ValueError when dividing by zero and otherwise returns the quotient. Write a test for the good path: safe_divide(10, 2) must return 5 — call first, then assert the value; an unexpected exception would fail the test by itself. Show the pytest -v output.
Output: complete Python program
Valid input, no exception

The Bad Path

The other half of the contract: bad input must raise. The call goes inside a with pytest.raises(ValueError) block — if the function returns a number instead of raising, the test fails.

Naming the exception class matters: the block only accepts a ValueError, so a different, unexpected error still fails the test.

Bad input must raise

Dividing by zero has to fail. pytest.raises(ValueError) wraps the call safe_divide(10, 0). The function raises as promised, so the test passes.

Prompt
Write a Python test for the bad path of safe_divide: calling it with divisor 0 must raise ValueError. Wrap the call in a with pytest.raises(ValueError) block. Show the pytest -v output.
Output: complete Python program
Bad input must raise

A Table with want_error

Both paths fit into one parametrized test: give each case a want_error flag saying whether an exception is expected. The want value is None for that case, because a case that raises has no value to compare.

The test looks at want_error first. The expected failure is checked with pytest.raises and stops there; the other cases compare the value as usual.

Good and bad cases in one table

Four cases: three normal divisions and one division by zero with want_error=True. One parametrized test covers the whole contract of the function, and all four cases pass.

Prompt
Write a parametrized Python test for safe_divide where each case has an id, the two inputs, the expected value and a want_error flag. Use pytest.raises(ValueError) for the error case and compare the value for the others. Include three normal cases and one division by zero. Show the pytest -v output.
Output: complete Python program
Good and bad cases in one table