Python测试无法断言抛出ClientError异常问题排查
Let's break down why your test is failing with "Failed: DID NOT RAISE" and how to fix the client factory call count assertion.
Key Issues to Diagnose
First, the "DID NOT RAISE" error means your ContributionHandler isn't propagating the ClientError after exhausting retries. This usually happens because:
- Your mock isn't consistently throwing
ExpiredTokenerrors across all attempts - The retry logic isn't correctly triggering client reconstruction on
ExpiredToken - You're not letting the retry loop run until it hits the maximum retry limit
Step-by-Step Fixes
1. Ensure Consistent Mocked Errors
Your test needs to simulate that every call to create_contribution throws an ExpiredToken (a subclass of ClientError). If the mock stops throwing errors after the first retry, the handler will succeed silently instead of raising the expected exception.
Use side_effect on your mock client to repeat the error:
import pytest from your_module import ContributionHandler, ExpiredToken, ClientError def test_retry_on_expired_token(mocker): # Mock the client's create_contribution to always throw ExpiredToken mock_client = mocker.Mock() mock_client.create_contribution.side_effect = ExpiredToken("Token expired") # Mock the client factory to return our faulty client every time mock_client_factory = mocker.Mock(return_value=mock_client) # Initialize handler with 2 retries (so total 3 attempts: 1 initial + 2 retries) handler = ContributionHandler(client_factory=mock_client_factory, max_retries=2) # Verify that after all retries, the final error is raised with pytest.raises(ClientError): handler.create_contribution(your_args_here) # Assert the factory was called 3 times (once per attempt) assert mock_client_factory.call_count == 3
2. Validate Your Retry Logic
Double-check your ContributionHandler implementation to make sure it:
- Only retries on
ExpiredTokenspecifically (not allClientErrortypes) - Reconstructs the client on each retry
- Re-raises the error once retries are exhausted
Example correct retry logic:
class ContributionHandler: def __init__(self, client_factory, max_retries=2): self.client_factory = client_factory self.max_retries = max_retries self.client = client_factory() def create_contribution(self, ...): retries = 0 while True: try: return self.client.create_contribution(...) except ExpiredToken as e: if retries >= self.max_retries: # No more retries - propagate the error raise # Recreate client and increment retry counter self.client = self.client_factory() retries += 1 except ClientError as e: # Other client errors don't trigger retries raise
3. Match Retry Count to Factory Call Count
If you're asserting 3 factory calls, make sure your max_retries is set to 2 (since initial client creation + 2 retries = 3 total factory invocations). If your handler uses a different retry count, adjust the assertion accordingly.
Common Pitfalls to Avoid
- Forgetting that the initial client is created in
__init__(so factory calls = 1 + max_retries) - Using a mock that only throws the error once (so the retry succeeds on the next attempt)
- Accidentally catching all
ClientErrortypes instead of justExpiredTokenfor retries
内容的提问来源于stack exchange,提问作者user12042028

