Python unittest无法Mock私有方法及IndexError问题排查求助
问题分析:ZipService单元测试出现IndexError的原因及解决提示
我有一个核心类ZipService,用于读取S3上的ZIP文件、解压并获取其中manifest.json的内容,功能运行正常。但在使用Python unittest对其进行Mock测试时出现错误,报错信息为IndexError: list index out of range。以下是类代码、测试代码及错误详情,求问题定位提示。
类代码
class ZipService: def __init__(self, path: str): self.path = path def get_manifest_json_object(self): s3 = boto3.resource('s3') bucket_name, key = self.__get_bucket_and_key() bucket = s3.Bucket(bucket_name) zip_object_reference = bucket.Object(key).get()["Body"] zip_object_bytes_stream = self.__get_zip_object_bytes_stream(zip_object_reference) zipf = zipfile.ZipFile(zip_object_bytes_stream, mode='r') return self.__get_manifest_json(zipf) def __get_bucket_and_key(self): pattern = "https:\/\/(.?[^\.]*)\.(.?[^\/]*)\/(.*)" # this regex is working but don't know how :D result = re.split(pattern, self.path) return result[1], result[3] def __get_zip_object_bytes_stream(self, zip_object_reference): return io.BytesIO(zip_object_reference.read()) def __get_manifest_json(self, zipf): manifest_json_text = [zipf.read(name) for name in zipf.namelist() if "/manifest.json" in name][0].decode("utf-8") return json.loads(manifest_json_text)
测试代码
@patch('boto3.resource') class TestZipService(TestCase): def test_zip_service(self, mock): s3 = boto3.resource('s3') bucket = s3.Bucket("abc") bucket.Object.get.return_value = "some-value" zipfile.ZipFile.return_value = "/some-path" inst = ZipService("/some-path") with mock.patch.object(inst, "_ZipService__get_manifest_json", return_value={"a": "b"}) as some_object: expected = {"a": "b"} actual = inst.get_manifest_json_object() self.assertIsInstance(expected, actual)
错误信息
bucket_name, key = self.__get_bucket_and_key() File "/Us.tox/py38/lib/python3.8/site-packages/services/zip_service.py", line 29, in __get_bucket_and_key return result[1], result[3] IndexError: list index out of range
问题定位
- 正则匹配完全失败:测试中传入的路径是
"/some-path",但__get_bucket_and_key方法里的正则是专门匹配S3的HTTPS格式路径(比如https://bucket.s3.amazonaws.com/key.zip),这个测试路径完全不符合正则规则,导致re.split返回的列表长度远小于预期,访问result[1]和result[3]时直接触发索引越界。 - 测试逻辑遗漏关键Mock:你只Mock了
__get_manifest_json,但get_manifest_json_object执行时会先调用__get_bucket_and_key,这个私有方法没有被Mock,会真实执行,而传入的测试路径不合法,直接引发错误。
解决提示
- Mock私有方法跳过正则匹配:在测试中直接Mock
__get_bucket_and_key,让它返回合法的bucket和key,避免正则匹配环节出错。示例:with mock.patch.object(inst, "_ZipService__get_bucket_and_key", return_value=("test-bucket", "test-key.zip")): expected = {"a": "b"} actual = inst.get_manifest_json_object() self.assertEqual(expected, actual) - 传入符合规则的测试路径:把测试中
ZipService的初始化路径改成符合正则的格式,比如"https://test-bucket.s3.amazonaws.com/test-zip.zip"。 - 修复正则表达式的语法错误:当前正则里的
.?是无效的,应该改成.*?(非贪婪匹配),修正后的正则更可靠:r"https://(.*?)\.(.*?)/(.*)"。 - 修正断言逻辑错误:测试里用了
self.assertIsInstance(expected, actual),这个方法是判断actual是不是expected的实例,你实际需要的是判断两个字典内容相等,应该用self.assertEqual(expected, actual)。
内容的提问来源于stack exchange,提问作者whatsinthename
相关产品推荐
相关产品推荐

