Моя среда состоит из Python 3.7.5 и притока-клиента библиотеки версии 1.9.0
. Я хочу смоделировать метод 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)
Моя отладка проблемы (если актуально для ответа)
Исправление объекта InfluxDB
напрямую (test_patching_InfluxDB
) вызывает AttributeError
с жалобой на то, что не ' может иметь атрибут select_where
. Однако , глядя на исходный код , указывает, что InfluxDB
действительно имеет метод класса с именем select_where
. Что мешает, так это то, что класс украшен @pytool.lang.hashed_singleton
, см. Фрагмент документации:
Оборачивает класс, чтобы создать его хешированную одноэлементную версию. Хешированный синглтон подобен синглтону в том, что для каждой сигнатуры вызова будет только один экземпляр класса.
Синглтон сохраняется как слабая ссылка, поэтому, если ваша программа перестает ссылаться на хешированный синглтон, вы можете получить новый экземпляр, если интерпретатор Python собрал мусор вашего исходного экземпляра.
- https://pytool.readthedocs.io/en/latest/pytool.html#pytool .lang.hashed_singleton
После этого я попробовал второй способ исправления объекта (test_patching_client
), думая, что если бы я создал экземпляр InfluxDB
с теми же параметрами в тестах, что и в исходном коде, экземпляры были бы одним и тем же объектом, что позволило бы мне смоделировать метод в тестах и перезаписать его в обоих местах. Но это привело к ошибке атрибута только для чтения, так что теперь у меня нет идей.