如何用botocore Stubber测试调用boto3 resource的Python函数
解决boto3 Resource结合Stubber单元测试时的UnStubbedResponseError问题
问题场景
使用boto3 Resource编写了simpleput函数,尝试用botocore Stubber编写单元测试时,出现错误:
botocore.exceptions.UnStubbedResponseError: Error getting response stub for operation PutObject: Unexpected API Call: A call was made but no additional calls expected. Either the API Call was not stubbed or it was called multiple times.
不清楚如何正确注入/拦截目标函数的S3调用。
业务代码(simpleput.py)
s3 = boto3.resource('s3') def simpleput(bucket: str, filename: str): s3bucket = s3.Bucket(bucket) s3.Object(bucket, filename).put(Body='one\ntwo')
问题分析
测试代码存在两个核心问题:
- 在
with stubber块内手动调用了client.put_object,提前消耗了唯一的桩化响应,导致后续被测函数调用PutObject时无桩可用 - 冗余调用导致桩化次数不匹配,触发未预期调用的错误
修正后的测试代码
import unittest import boto3 from botocore.stub import Stubber import simpleput class TestModule(unittest.TestCase): def test_seed(self): # 创建带桩的S3资源实例 s3_resource = boto3.resource('s3') client = s3_resource.meta.client stubber = Stubber(client) # 替换被测模块中的全局s3实例 simpleput.s3 = s3_resource # 定义桩化响应和预期参数 response = {"Expiration": "whatever", "ETag": "12345", "VersionId": "1.0"} expected_params = { "Body": 'one\ntwo', "Bucket": 'mybucket', "Key": 'mykey', } stubber.add_response('put_object', response, expected_params) # 在桩上下文内执行被测函数 with stubber: simpleput.simpleput('mybucket', 'mykey') # 验证所有桩化调用都已被触发 stubber.assert_no_pending_responses()
关键修正点
- 移除了手动调用的
client.put_object,避免提前消耗桩化响应 - 使用
stubber.assert_no_pending_responses()确保被测函数触发了预期的API调用 - 确保被测模块使用的是我们创建的带桩的S3资源实例
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

