如何在Python单元测试中模拟hashed_singleton对象?

时间:2020-01-17 11:47:56

标签: unit-testing influxdb-python

我的环境包含版本为1.9.0的Python 3.7.5和influx-client库。我想模拟select_where对象的InfluxDB方法,但是在我的代码(如下所示)中,它导致AttributeError出现,例如

AttributeError: <class 'influx.InfluxDB'> does not have the attribute 'select_where'

AttributeError: 'InfluxDB' object attribute 'select_where' is read-only

用于复制的最小代码

influx_mock
├── db_connection
│   ├── __init__.py
│   └── __main__.py
└── tests
    └── test_db_connection.py

文件内容:

# db_connection/__main__.py

from influx import InfluxDB


def get_data(influx_url):
    client = InfluxDB(influx_url)
    return client.select_where(
        'database', 
        'measurement',
        fields='foo',
        where='bar > 0'
    )

if __name__ == "__main__":
    influx_url = 'http://127.0.0.1:8086'
    data = get_data(influx_url)
    # ...process data
# db_connection/__init__.py

from .__main__ import get_data
# tests/test_db_connection

import unittest
from unittest.mock import patch

from influx import InfluxDB

from db_connection import get_data


class DbConnection(unittest.TestCase):

    def setUp(self):
        self.influx_url = 'http://127.0.0.1:8086'
        self.mock_data = { 'mock data' }

    def test_patching_InfluxDB(self):
        with patch.object(InfluxDB, 'select_where', return_value=self.mock_data):
            data = get_data(self.influx_url)
            self.assertEqual(self.mock_data, data)

    def test_patching_client(self):
        client = InfluxDB(self.influx_url)
        with patch.object(client, 'select_where', return_value=self.mock_data):
            data = get_data(self.influx_url)
            self.assertEqual(self.mock_data, data)

使用python -m unittest discover -s tests/运行单元测试会导致

EE
======================================================================
ERROR: test_patching_InfluxDB (test_db_connection.DbConnection)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<redacted>/influx_mock/tests/test_db_connection.py", line 17, in test_patching_InfluxDB
    with patch.object(InfluxDB, 'select_where', return_value=self.mock_data):
  File "<redacted>/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py", line 1319, in __enter__
    original, local = self.get_original()
  File "<redacted>/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py", line 1293, in get_original
    "%s does not have the attribute %r" % (target, name)
AttributeError: <class 'influx.InfluxDB'> does not have the attribute 'select_where'

======================================================================
ERROR: test_patching_client (test_db_connection.DbConnection)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<redacted>/influx_mock/tests/test_db_connection.py", line 24, in test_patching_client
    with patch.object(client, 'select_where', return_value=self.mock_data):
  File "<redacted>/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py", line 1410, in __enter__
    setattr(self.target, self.attribute, new_attr)
AttributeError: 'InfluxDB' object attribute 'select_where' is read-only

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (errors=2)

我对问题的调试(如果与答案有关)

直接修补对象InfluxDBtest_patching_InfluxDB)引发AttributeError,抱怨它不具有属性select_where 。但是,looking at the source code表示InfluxDB确实具有称为select_where的类方法。令人困惑的是,该类用@pytool.lang.hashed_singleton装饰,请参见文档中的摘录:

包装一个类以创建它的哈希单例版本。散列的单例就像单例,因为每个呼叫签名只有一个类的实例。

单例保持为弱引用,因此,如果您的程序停止引用散列的单例,则如果Python解释器已垃圾回收原始实例,则可能会得到一个新实例。

-https://pytool.readthedocs.io/en/latest/pytool.html#pytool.lang.hashed_singleton

在碰上这个问题之后,我尝试了第二种修补对象(test_patching_client)的方法,认为如果我创建了一个InfluxDB实例,并且该实例在测试中与源代码中的参数相同,则该实例将是相同的对象使我可以在测试中模拟该方法,从而在两个地方都将其覆盖。但这导致了只读属性错误,所以现在我没有主意了。

0 个答案:

没有答案