如何正确Mock全局作用域中的Python模块变量boto3.client?
如何正确Mock全局作用域中的boto3.client
问题根源
你的原始ecr.py中,client = boto3.client('ecr')属于模块级全局变量,在模块被Python解释器加载时就会执行并实例化真实的ECR客户端。而测试代码中的mock.patch('boto3.client')是在测试函数运行时才生效,此时全局client已经被创建,mock无法回溯修改已存在的实例,导致测试不生效。
解决方案1:直接Mock模块内的全局client变量
不需要修改业务代码,直接针对被测模块里的全局client对象进行mock,替换它的方法行为:
import unittest from unittest import mock from mirror import ecr_service class TestEcrService(unittest.TestCase): def test_get_tags(self): # 替换ecr_service模块里的全局client变量为mock对象 with mock.patch('mirror.ecr_service.client') as mock_client: # 预设list_images方法的返回值 mock_client.list_images.return_value = { 'imageIds': [ {'imageTag': 'v2.33.4'}, {'imageTag': 'v2.33.3'} ] } tags = ecr_service.get_tags('prometheus') self.assertEqual(['v2.33.4', 'v2.33.3'], tags)
这种方式跳过了对boto3.client的mock,直接针对已存在的全局客户端实例做行为模拟,能快速适配原有代码结构。
解决方案2:重构业务代码(你已采用的方案)
将客户端实例化逻辑从全局移到函数内部,这样每次调用get_tags时都会重新调用boto3.client,此时测试中的mock.patch('boto3.client')就能生效:
重构后的ecr.py
import boto3 def get_tags(repository): response = boto3.client('ecr').list_images(repositoryName=repository) tags = [image['imageTag'] for image in response['imageIds']] return tags
对应的测试代码
import unittest from unittest import mock from mirror import ecr_service from tests import fake_requests class TestEcrService(unittest.TestCase): def test_get_tags(self): with mock.patch('boto3.client', fake_requests.fake_client): tags = ecr_service.get_tags('prometheus') self.assertEqual(['v2.33.4', 'v2.33.3'], tags)
这种方案从根源上消除了全局状态带来的测试不确定性,让代码更易于维护和扩展,是更推荐的长期解决方案。
内容的提问来源于stack exchange,提问作者Andre Fagundes
相关产品推荐
相关产品推荐

