An exception chain happens when one exception causes another. It shows the sequence of errors leading to the final failure. Testing exception chains helps check if the right errors happen in the right order.
Click to reveal answer
intermediate
How do you test exception chains using pytest?
Use pytest.raises() with the 'match' parameter to check the final exception message. To check the chain, access the '__cause__' or '__context__' attributes of the caught exception inside the 'as excinfo' block.
Click to reveal answer
intermediate
What is the difference between __cause__ and __context__ in exception chaining?
__cause__ is set when an exception is raised directly from another using 'raise ... from ...'. __context__ is set automatically when an exception occurs during handling another exception without 'from'.
Click to reveal answer
intermediate
Write a simple pytest test snippet to check an exception chain where ValueError causes a RuntimeError.
def test_exception_chain():
import pytest
with pytest.raises(RuntimeError) as excinfo:
try:
raise ValueError("bad value")
except ValueError as e:
raise RuntimeError("runtime failed") from e
assert isinstance(excinfo.value.__cause__, ValueError)
assert str(excinfo.value.__cause__) == "bad value"
Click to reveal answer
beginner
Why is testing exception chains important in software testing?
It ensures that errors are handled properly and the root cause is not lost. This helps developers understand what really went wrong and fix bugs faster.
Click to reveal answer
In pytest, which attribute holds the original exception when using 'raise ... from ...'?
A__cause__
B__context__
C__traceback__
D__exception__
✗ Incorrect
The __cause__ attribute stores the original exception when an exception is raised from another using 'raise ... from ...'.
What does pytest.raises() do in a test?
ACatches all exceptions silently
BChecks if a block of code raises a specific exception
CPrevents exceptions from happening
DLogs exceptions to a file
✗ Incorrect
pytest.raises() verifies that the code inside its block raises the expected exception.
If an exception occurs during handling another exception without 'from', which attribute links them?
A__cause__
B__linked__
C__handler__
D__context__
✗ Incorrect
__context__ links exceptions when one happens during handling another without explicit chaining.
Which pytest feature helps check the message text of an exception?
Aexception_message()
BassertRaisesMessage()
Cmatch parameter in pytest.raises()
Dcheck_message()
✗ Incorrect
The 'match' parameter in pytest.raises() lets you check if the exception message matches a pattern.
Why should you test exception chains instead of just the final exception?
ATo verify the root cause and error flow
BTo make tests run faster
CTo avoid writing assertions
DTo skip error handling
✗ Incorrect
Testing chains helps confirm the root cause and the sequence of errors, improving debugging.
Explain how to test an exception chain in pytest with an example.
Think about how to access the original exception inside the pytest.raises block.
You got /4 concepts.
Describe the difference between __cause__ and __context__ in Python exception chaining.
One is set explicitly, the other automatically.
You got /3 concepts.
Practice
(1/5)
1. What is the main purpose of testing exception chains in pytest?
easy
A. To test if exceptions are ignored during execution
B. To check if the test function runs without any exceptions
C. To ensure the program does not raise any exceptions
D. To verify that an exception was raised and linked to its cause
Solution
Step 1: Understand exception chains
Exception chains link one error to another, showing the root cause of a failure.
Step 2: Purpose of testing chains in pytest
Testing exception chains ensures both the raised exception and its cause are correct.
Final Answer:
To verify that an exception was raised and linked to its cause -> Option D
Quick Check:
Exception chains test = verify raised exception and cause [OK]
Hint: Check both exception and cause to test chains correctly [OK]
Common Mistakes:
Ignoring the cause of the exception
Only checking if any exception was raised
Assuming no exceptions means success
2. Which of the following is the correct syntax to test an exception chain using pytest?
easy
A. with pytest.raises(ValueError) as excinfo:
raise TypeError() from ValueError()
B. with pytest.raises(TypeError) as excinfo:
raise TypeError() from ValueError()
C. with pytest.raises(TypeError) as excinfo:
raise ValueError() from None
D. with pytest.raises(TypeError) as excinfo:
raise ValueError() from TypeError()
Solution
Step 1: Understand exception chaining syntax
Python uses raise NewException() from OriginalException() to chain exceptions.
Step 2: Match pytest.raises with the raised exception
The pytest.raises() context must match the exception actually raised, here TypeError.
Final Answer:
with pytest.raises(TypeError) as excinfo:
raise TypeError() from ValueError() -> Option B
Quick Check:
pytest.raises matches raised exception, not cause [OK]
Hint: pytest.raises matches raised exception, not the cause [OK]
Common Mistakes:
Matching pytest.raises to the cause exception
Swapping raised and cause exceptions
Using None as cause incorrectly
3. Given the code below, what will excinfo.value.__cause__ be?
def func():
try:
raise ValueError("original error")
except ValueError as e:
raise TypeError("new error") from e
def test_func():
with pytest.raises(TypeError) as excinfo:
func()
medium
A. None
B. AttributeError
C. ValueError('original error')
D. TypeError('new error')
Solution
Step 1: Analyze exception chaining in func()
ValueError is raised first, caught, then TypeError is raised from it, linking ValueError as cause.
Step 2: Understand excinfo.value.__cause__
It holds the original exception that caused the current one, so it will be the ValueError instance.
Final Answer:
ValueError('original error') -> Option C
Quick Check:
__cause__ stores original exception in chain [OK]
Hint: __cause__ holds the original exception object [OK]
Common Mistakes:
Expecting __cause__ to be None
Confusing __cause__ with the raised exception
Assuming __cause__ is a string
4. Identify the error in this pytest test for exception chains:
def test_chain():
with pytest.raises(TypeError) as excinfo:
raise TypeError("error") from ValueError("cause")
assert isinstance(excinfo.value.__cause__, TypeError)
medium
A. The assertion checks wrong exception type for __cause__
B. The exception chaining syntax is invalid
C. The raised exception and pytest.raises do not match
D. No error, test is correct
Solution
Step 1: Check raised exception and pytest.raises
pytest.raises expects TypeError, but TypeError is raised from ValueError, so this is valid.
Step 2: Analyze assertion on __cause__
__cause__ is the original exception, here ValueError, but assertion checks for TypeError incorrectly.
Final Answer:
The assertion checks wrong exception type for __cause__ -> Option A
Quick Check:
__cause__ is original exception, check its correct type [OK]
Hint: Assert __cause__ type matches original exception, not raised one [OK]
Common Mistakes:
Confusing raised exception with __cause__
Assuming __cause__ is None
Ignoring mismatch between pytest.raises and raised exception
5. You want to test a function that raises a RuntimeError caused by a KeyError. Which pytest test code correctly verifies both exceptions?
hard
A. with pytest.raises(RuntimeError) as excinfo:
func()
assert isinstance(excinfo.value.__cause__, KeyError)
B. with pytest.raises(KeyError) as excinfo:
func()
assert isinstance(excinfo.value.__cause__, RuntimeError)
C. with pytest.raises(RuntimeError) as excinfo:
func()
assert excinfo.value.__cause__ is None
D. with pytest.raises(Exception) as excinfo:
func()
assert isinstance(excinfo.value.__cause__, RuntimeError)
Solution
Step 1: Match pytest.raises to the raised exception
The function raises RuntimeError, so pytest.raises must expect RuntimeError.
Step 2: Check the cause exception
The cause is KeyError, so assert __cause__ is instance of KeyError.
Final Answer:
with pytest.raises(RuntimeError) as excinfo:
func()
assert isinstance(excinfo.value.__cause__, KeyError) -> Option A
Quick Check:
pytest.raises matches raised, assert __cause__ matches cause [OK]
Hint: pytest.raises for raised, assert __cause__ for cause exception [OK]
Common Mistakes:
Swapping raised and cause exceptions in pytest.raises
Asserting __cause__ is None incorrectly
Using too broad exception in pytest.raises
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.