在Python unittest中BytesIO对象的断言错误

huangapple go评论66阅读模式
英文:

Assertion error for BytesIO object in Python unittest

问题

以下是要翻译的内容:

I have a core logic classes like below:

class SomeDBTManifestProvider:

    def __init__(self):
        pass

    def extract_manifest_json(self, file_stream: BytesIO):
        try:
            zipf = zipfile.ZipFile(file_stream)
            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)
        except Exception as e:
            raise FetchManifestJsonException(e)


class DbtProvisioner(object):

    def __init__(self, dbt_manifest_provider: SomeDBTManifestProvider):
        self.dbt_manifest_provider = dbt_manifest_provider
        
    def provision(self, provision_request: ProvisionRequest):
        self.dbt_manifest_provider.extract_manifest_json(BytesIO(b'ABC'))
        return "Success"  

Where ProvisionRequest is nothing but a DataClass and it can be ignored for now. As it can be seen DbtProvisioner is dependent on SomeDBTManifestProvider, therefore I have used D.I to access the method of SomeDBTManifestProvider. Now, I want to test DbtProvisioner for which I wrote the below test case:

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(BytesIO(b'ABC'))
        self.assertEqual("Success", actual)  

Now, using the above approach I want to ensure that my method has been called with the right set of arguments. But somehow, it is giving me the below error:

Expected: extract_manifest_json(<_io.BytesIO object at 0x10d675900>)
Actual: extract_manifest_json(<_io.BytesIO object at 0x10f8efef0>)

How do I resolve this error? What am I missing here?

I also referred to multiple articles from SO but didn't help in any way. TIA

英文:

I have a core logic classes like below:

class SomeDBTManifestProvider:

    def __init__(self):
        pass

    def extract_manifest_json(self, file_stream: BytesIO):
        try:
            zipf = zipfile.ZipFile(file_stream)
            manifest_json_text = [zipf.read(name) for name in zipf.namelist() if &quot;/manifest.json&quot; in name][0].decode(&quot;utf-8&quot;)
            return json.loads(manifest_json_text)
        except Exception as e:
            raise FetchManifestJsonException(e)


class DbtProvisioner(object):

    def __init__(self, dbt_manifest_provider: SomeDBTManifestProvider):
        self.dbt_manifest_provider = dbt_manifest_provider
        
    def provision(self, provision_request: ProvisionRequest):
        self.dbt_manifest_provider.extract_manifest_json(BytesIO(b&#39;ABC&#39;))
        return &quot;Success&quot;  

Where ProvisionRequest is nothing but a DataClass and it can be ignored for now. As it can be seen DbtProvisioner is dependent on SomeDBTManifestProvider, therefore I have used D.I to access the method of SomeDBTManifestProvider. Now, I want to test DbtProvisioner for which I wrote the below test case:

def test_dbt_provision(self):
        provision_request = ProvisionRequest(
            DataProduct(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;, &quot;f&quot;, {}, [{}]), Workload(&quot;ab&quot;, &quot;cd&quot;, &quot;ef&quot;, &quot;gh&quot;, DbtAttr(&quot;path&quot;))
        )
        dbt_manifest = Mock()
        actual = DbtProvisioner(dbt_manifest).provision(
            provision_request)
        dbt_manifest.extract_manifest_json.assert_called_with(BytesIO(b&#39;ABC&#39;))
        self.assertEqual(&quot;Success&quot;, actual)  

Now, using the above approach I want to ensure that my method has been called with the right set of arguments. But somehow, it is giving me the below error:

Expected: extract_manifest_json(&lt;_io.BytesIO object at 0x10d675900&gt;)
Actual: extract_manifest_json(&lt;_io.BytesIO object at 0x10f8efef0&gt;)

How do I resolve this error? What am I missing here?

I also referred to multiple articles from SO but didn't help in any way. TIA

答案1

得分: 1

问题在于BytesIO对象的比较是基于身份(identity)而不是内容(content),所以虽然b'ABC' == b'ABC'是正确的,但BytesIO(b'ABC') == BytesIO(b'ABC')是错误的,因为它们是两个不同的BytesIO对象。

为了按预期执行您的测试,一个解决方法是使用getvalue方法提取作为调用参数使用的BytesIO对象的值,该值可以在Mock对象的mock_calls属性中找到。

将:

dbt_manifest.extract_manifest_json.assert_called_with(BytesIO(b'ABC'))

改为:

self.assertEqual(dbt_manifest.extract_manifest_json.mock_calls[0].args[0].getvalue(), b'ABC')
英文:

The problem is that BytesIO objects do not compare to each other based on content, but identity, so while b&#39;ABC&#39; == b&#39;ABC&#39; is true, BytesIO(b&#39;ABC&#39;) == BytesIO(b&#39;ABC&#39;) is not because they are two different BytesIO objects.

To perform your test as desired, a workaround would be to use the getvalue method to extract the value of the BytesIO object used as the argument of the call, which can be found in the mock_calls attribute of the Mock object.

Change:

dbt_manifest.extract_manifest_json.assert_called_with(BytesIO(b&#39;ABC&#39;))

to:

self.assertEqual(dbt_manifest.extract_manifest_json.mock_calls[0].args[0].getvalue(), b&#39;ABC&#39;))

huangapple
  • 本文由 发表于 2023年3月1日 16:46:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75601358.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定