Python单元测试中BytesIO对象断言错误的排查与解决
问题原因
你遇到的断言失败是因为:测试代码里创建的BytesIO(b'ABC')和被测试方法provision内部创建的BytesIO(b'ABC')是两个独立的对象实例,内存地址不同,直接用assert_called_with比较实例会判定不匹配。
解决方法
这里提供三种可行的解决思路:
1. 验证参数的内容而非实例(最直接的修复)
不需要修改原业务代码,直接在测试里获取调用参数,读取BytesIO的内容进行比较:
def test_dbt_provision(self): provision_request = ProvisionRequest( DataProduct("a", "b", "c", "d", "e", "f", {}, [{}]), Workload("ab", "cd", "ef", "gh", DbtAttr("path")) ) dbt_manifest = Mock() actual = DbtProvisioner(dbt_manifest).provision(provision_request) # 获取调用时的第一个位置参数 actual_stream = dbt_manifest.extract_manifest_json.call_args[0][0] # 重置流的指针到开头(因为流可能被读取过) actual_stream.seek(0) # 比较流的内容 self.assertEqual(actual_stream.read(), b'ABC') self.assertEqual("Success", actual)
2. 使用ANY忽略实例,仅验证类型(适合只关心参数类型的场景)
如果不需要验证具体内容,只需要确认传入的是BytesIO对象,可以用unittest.mock.ANY:
from unittest.mock import Mock, ANY def test_dbt_provision(self): provision_request = ProvisionRequest( DataProduct("a", "b", "c", "d", "e", "f", {}, [{}]), Workload("ab", "cd", "ef", "gh", DbtAttr("path")) ) dbt_manifest = Mock() actual = DbtProvisioner(dbt_manifest).provision(provision_request) dbt_manifest.extract_manifest_json.assert_called_with(ANY) # 可选:进一步验证参数类型 self.assertIsInstance(dbt_manifest.extract_manifest_json.call_args[0][0], BytesIO) self.assertEqual("Success", actual)
3. 重构业务代码,注入流对象(更优雅的测试友好写法)
把BytesIO的创建逻辑从provision方法中抽离,允许外部注入,这样测试时可以传入同一个实例:
修改业务代码
class DbtProvisioner(object): def __init__(self, dbt_manifest_provider: SomeDBTManifestProvider): self.dbt_manifest_provider = dbt_manifest_provider def provision(self, provision_request: ProvisionRequest, file_stream: BytesIO = None): # 提供默认值,不影响原有调用逻辑 if file_stream is None: file_stream = BytesIO(b'ABC') self.dbt_manifest_provider.extract_manifest_json(file_stream) return "Success"
修改测试代码
def test_dbt_provision(self): provision_request = ProvisionRequest( DataProduct("a", "b", "c", "d", "e", "f", {}, [{}]), Workload("ab", "cd", "ef", "gh", DbtAttr("path")) ) test_stream = BytesIO(b'ABC') dbt_manifest = Mock() actual = DbtProvisioner(dbt_manifest).provision(provision_request, test_stream) # 现在可以直接断言同一个实例 dbt_manifest.extract_manifest_json.assert_called_with(test_stream) self.assertEqual("Success", actual)
内容的提问来源于stack exchange,提问作者whatsinthename
相关产品推荐
相关产品推荐

