-
-
Notifications
You must be signed in to change notification settings - Fork 362
Add assert_on_exception parameter to add context to test failures
#782
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
When set to True, assertions about unfired requests will be raised even when an exception occurs in the context manager. This provides valuable debugging context about which mocked requests were or weren't called when debugging test failures. By default (assert_on_exception=False), the assertion is suppressed to avoid masking the original exception. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
assert_on_exception parameter to add context to test failures
| raise ValueError("Main error") | ||
|
|
||
| # The AssertionError should mention the unfired request | ||
| assert "not-called.com" in str(assert_exc_info.value) |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization
| m.add(responses.GET, "http://not-called.com", body=b"test") | ||
| requests.get("http://example.com") | ||
|
|
||
| assert "not-called.com" in str(assert_exc_info2.value) |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization
| test_with_assert_on_exception() | ||
|
|
||
| # The AssertionError should mention the unfired request | ||
| assert "not-called.com" in str(assert_exc_info.value) |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization
| with pytest.raises(ValueError) as value_exc_info: | ||
| with responses.RequestsMock( | ||
| assert_all_requests_are_fired=True, assert_on_exception=False | ||
| ) as m: | ||
| m.add(responses.GET, "http://example.com", body=b"test") | ||
| m.add(responses.GET, "http://not-called.com", body=b"test") | ||
| requests.get("http://example.com") | ||
| raise ValueError("Main error") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is arguable that this behaviour is a bug. And that assert_on_exception doesn't need to exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with changing this behaviour without an opt-in feature flag is that it'd be a breaking change, as the tests demonstrate (the exception leaving the RequestsMock block would change).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree that the exception type changing because the library has become more strict/correct constitutes a breaking change. Following that line of thinking would imply that no additional exception types could be added as they could 'break' compatibility.
| with pytest.raises(AssertionError) as assert_exc_info: | ||
|
|
||
| @responses.activate( | ||
| assert_all_requests_are_fired=True, assert_on_exception=True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like assert_on_exception is a noop when used by itself, which feels like it is a sub-optimal design choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could make assert_on_exception imply assert_all_requests_are_fired, but I'm not sure that's better. We could raise an exception if assert_all_requests_are_fired is False but assert_on_exception is True? That's trivial to do when instantiating RequestsMock; a bit trickier to do with the decorator since it mocks the attributes on RequestsMock.
The @responses.activate decorator now accepts an assert_on_exception
parameter, providing a convenient way to enable assertion checking
even when exceptions occur:
@responses.activate(
assert_all_requests_are_fired=True,
assert_on_exception=True
)
def test_my_api():
...
This is consistent with the existing decorator support for
assert_all_requests_are_fired and registry parameters.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Document the new assert_on_exception parameter in version 0.26.0. This is a minor version bump (not patch) because we're adding new functionality to the public API, even though it's fully backward compatible with existing code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7a49723 to
c27fb47
Compare
What type of PR is this? (check all applicable)
Description
When a test fails within the scope of
RequestsMock(e.g. an exception is raised or an assertion fails),responsesskips asserting that all requests were fired. This can hide useful information for debugging the test, as the test failure may have been a side effect of an expected request not being called (e.g. the mocked URL was wrong). This leaves users with an awkward choice - perform all of their assertions outside of theRequestsMockscope in order to always see when expected requests were not called (but lose the context those assertions would provide) or perform the assertions within theRequestsMockscope and lose the context of which requests were not called.This PR introduces a new
assert_on_exceptionparameter to theRequestsMockclass and@responses.activatedecorator. This feature eliminates the need for the aforementioned awkward choice by allowing the user to opt into always having it asserted that all requests were fired, even in the case that the test is already failing for some reason. The resulting test failure message will mention both the failingresponsesassertion and the original error message, giving the user the most context as to why the test is failing.Key Changes
assert_on_exceptionboolean parameter toRequestsMockconstructor@responses.activatedecorator to accept the new parameterassert_on_exception=True, request assertions are raised even during exceptions, providing context about which mocked requests were or weren't calledassert_on_exception=False)Usage Examples
Context Manager Usage:
Decorator Usage:
Benefits
Related Issues
PR checklist
Before submitting this pull request, I have done the following:
toxandpre-commitchecks locallyAdded/updated tests?
Test Coverage: Comprehensive tests added covering: