如何复用方法内mock的s3连接 避免为所有测试方法标注@mock_s3
实现思路及方案
你当前的写法存在作用域问题:
@mock_s3装饰get_s3_bucket方法时,mock仅在该方法运行期间生效,方法执行完成后mock会自动销毁,你在测试方法中拿到bucket对象后再操作时,boto3会恢复真实请求逻辑,无法达到mock效果。
方案1:直接装饰测试类(最简实现)
moto的mock装饰器支持直接装饰unittest测试类,类下所有测试方法都会自动处于mock s3环境中,无需逐个方法加装饰器:
import unittest import boto3 from moto import mock_s3 bucket_name = "test-bucket" @mock_s3 class App_Test(unittest.TestCase): def setUp(self): # 每个测试方法运行前自动执行,初始化干净的mock桶 self.s3_resource = boto3.resource('s3') self.s3_bucket = self.s3_resource.create_bucket(Bucket=bucket_name) def some_test(self): # 直接调用self.s3_bucket操作即可,全程处于mock环境 self.s3_bucket.put_object(Key="test.txt", Body=b"test content") obj = self.s3_resource.Object(bucket_name, "test.txt").get() self.assertEqual(obj['Body'].read(), b"test content") def some_test_123(self): # 同样直接使用self.s3_bucket,和其他测试方法数据隔离 pass
方案2:手动控制mock生命周期(灵活控制生效范围)
如果你不需要整个类的所有测试都启用mock s3,可以调用mock实例的start()和stop()方法手动控制生命周期:
class App_Test(unittest.TestCase): def setUp(self): self.mock_s3 = mock_s3() # 手动启动mock self.mock_s3.start() self.s3_bucket = boto3.resource('s3').create_bucket(Bucket=bucket_name) def tearDown(self): # 测试结束后手动停止mock,还原boto3原生行为 self.mock_s3.stop() def some_test(self): # 该测试方法在mock环境下运行 pass def test_with_real_s3(self): # 如果不需要mock,可以在方法开头先调用self.mock_s3.stop()即可 pass
方案3:封装基类实现多测试类复用
如果有多个测试类都需要用到mock s3,可以把mock逻辑封装成公共基类,其他测试类直接继承即可:
@mock_s3 class S3MockTestBase(unittest.TestCase): bucket_name = "test-bucket" def setUp(self): super().setUp() self.s3_resource = boto3.resource('s3') self.s3_bucket = self.s3_resource.create_bucket(Bucket=self.bucket_name) # 业务测试类直接继承即可复用mock逻辑 class App_Test(S3MockTestBase): def some_test(self): self.s3_bucket.put_object(Key="test.txt", Body=b"123") # 业务测试逻辑
注意事项
- 默认每个测试方法执行前都会重新运行
setUp初始化s3桶,不同测试方法的s3数据完全隔离,不会出现交叉污染 - 如果需要所有测试方法共用同一套s3预置数据,可以把初始化逻辑放到
setUpClass类方法中,注意做好数据清理避免互相影响
内容的提问来源于stack exchange,提问作者Sai
相关产品推荐
相关产品推荐

