使用botocore Stubber时遭遇UnrecognizedClientException问题求助
That UnrecognizedClientException is a super common gotcha when stubbing AWS clients in unit tests—let’s break down why it’s happening and how to fix it quickly.
Why You’re Seeing This Error
Your my_function creates its own Athena client directly using boto3.client('athena') inside the function body. When you run your test, the stubbed client you’re setting up in test_my_function isn’t the one being used by my_function—the function is still trying to make a real AWS API call with an unauthenticated/incorrectly configured client, hence the authentication error.
Solution 1: Inject the Client into Your Function (Recommended)
The cleanest, most maintainable fix is to refactor your function to accept an Athena client as an optional parameter. This lets you pass in a stubbed client during testing, while keeping the default production behavior intact.
Modified Function Code
import boto3 def my_function(client=None): # Use the provided client, or create a new one if none is passed if client is None: client = boto3.client('athena') res = client.start_query_execution( # Note: Fixed typo here: exeuction → execution QueryString='SELECT * FROM logs', ResultConfiguration={'OutputLocation': 's3://mybucket'} ) return res['QueryExecutionId']
(Side note: I fixed a typo in start_query_exeuction—that would have caused another error once the stubbing was working correctly!)
Working Test Code with Stubber
Now you can create a stubbed Athena client, define the expected API response, and pass it directly to my_function:
from botocore.stub import Stubber import boto3 from your_module import my_function # Replace with your actual module name def test_my_function(): # Create a base Athena client to stub client = boto3.client('athena') with Stubber(client) as stubber: # Define the expected API call and mock response expected_query_id = 'test-query-id-123' stubber.add_response( 'start_query_execution', {'QueryExecutionId': expected_query_id}, { 'QueryString': 'SELECT * FROM logs', 'ResultConfiguration': {'OutputLocation': 's3://mybucket'} } ) # Call the function with our stubbed client result = my_function(client=client) # Verify the result matches our mock query ID assert result == expected_query_id # Optional: Ensure no unexpected API calls were made stubber.assert_no_pending_responses()
Solution 2: Monkeypatching (If You Can’t Refactor the Function)
If you can’t modify the original function to accept a client parameter, you can use monkeypatching to replace boto3.client with your stubbed client during the test:
from botocore.stub import Stubber import boto3 from unittest.mock import patch from your_module import my_function def test_my_function_with_monkeypatch(): client = boto3.client('athena') with Stubber(client) as stubber: expected_query_id = 'test-query-id-456' stubber.add_response( 'start_query_execution', {'QueryExecutionId': expected_query_id}, { 'QueryString': 'SELECT * FROM logs', 'ResultConfiguration': {'OutputLocation': 's3://mybucket'} } ) # Patch boto3.client to return our stubbed client with patch('boto3.client', return_value=client): result = my_function() assert result == expected_query_id stubber.assert_no_pending_responses()
Key Takeaways
- Dependency injection (passing the client into the function) is the best practice for writing testable AWS code—it keeps your tests isolated and avoids real API calls.
- Always ensure the stubbed client is the one being used by your function—otherwise, you’ll accidentally trigger real requests and hit auth errors.
- Double-check for typos in AWS API method names (like the one in your original code!)—they’re easy to miss and can derail your tests even after fixing stubbing issues.
内容的提问来源于stack exchange,提问作者LondonAppDev

