【问题标题】:Mocking elasticsearch-py calls模拟 elasticsearch-py 调用
【发布时间】:2018-05-24 09:55:13
【问题描述】:

我正在编写一个 CLI 以使用 elasticsearch-py 库与 elasticsearch 交互。我正在尝试模拟 elasticsearch-py 函数,以便在不调用我的真实集群的情况下测试我的函数。

我读了this questionthis one,但我还是不明白。

ma​​in.py

Escli继承自cliff的Appclass

class Escli(App):
    _es = elasticsearch5.Elasticsearch()

settings.py

from escli.main import Escli

class Settings:
    def get(self, sections):
        raise NotImplementedError()

class ClusterSettings(Settings):

    def get(self, setting, persistency='transient'):
        settings = Escli._es.cluster\
                    .get_settings(include_defaults=True, flat_settings=True)\
                    .get(persistency)\
                    .get(setting)

        return settings

settings_test.py

import escli.settings


class TestClusterSettings(TestCase):
    def setUp(self):
        self.patcher = patch('elasticsearch5.Elasticsearch')
        self.MockClass = self.patcher.start()

    def test_get(self):
        # Note this is an empty dict to show my point
        # it will contain childs dict to allow my .get(persistency).get(setting)
        self.MockClass.return_value.cluster.get_settings.return_value = {}

        cluster_settings = escli.settings.ClusterSettings()
        ret = cluster_settings.get('cluster.routing.allocation.node_concurrent_recoveries', persistency='transient')
        # ret should contain a subset of my dict defined above

我想让Escli._es.cluster.get_settings() 返回我想要的内容(dict 对象),以便不进行真正的 HTTP 调用,但它一直在这样做。

我所知道的:

  • 为了模拟实例方法,我必须执行类似的操作 MagicMockObject.return_value.InstanceMethodName.return_value = ...

  • 我无法修补 Escli._es.cluster.get_settings,因为 Python 尝试将 Escli 作为模块导入,但无法正常工作。所以我正在修补整个库。

我拼命想在任何地方放一些return_value,但我不明白为什么我不能正确地模拟那个东西。

【问题讨论】:

  • 你必须模拟你在哪里测试。由于您正在测试 settings.py 模块,因此您需要相应地引用您的模拟。因此,在您的setUp 中,您的patch 路径应该类似于:patch('escli.settings.Escli')。因此,现在当您像在测试中一样显式调用 settings 代码时,您现在可以在正确的位置正确地模拟了。
  • 此外,您可能希望使用 Elasticsearch 类指定您的 Mock,以验证您正在使用该类中可用的有效属性。因此,您可能需要执行以下操作:patch('escli.settings.Escli', Mock(Elasticsearch))
  • 只是把它放在那里,pytest 确实提供了一个插件,如果您也对其他选项感兴趣,您可以将其用于弹性搜索:pypi.org/project/pytest-elasticsearch
  • 你成就了我的一天!我会深入了解Mock() 的事情。您会考虑在解决此案时做出回答吗?
  • 很高兴它有帮助!我发布了答案。干杯。

标签: python unit-testing elasticsearch mocking


【解决方案1】:

你应该嘲笑你在哪里测试。根据提供的示例,这意味着您在settings.py 模块中使用的Escli 类需要针对settings.py 进行模拟。因此,更实际地,您的patch 调用在setUp 中看起来像这样:

self.patcher = patch('escli.settings.Escli')

有了这个,您现在可以根据测试的运行方式在正确的位置模拟您想要的内容。

此外,为了增加测试的稳健性,您可能需要考虑指定您正在创建的 Elasticsearch 实例,以验证您实际上正在调用与 Elasticsearch 相关的有效方法。考虑到这一点,您可以这样做:

self.patcher = patch('escli.settings.Escli', Mock(Elasticsearch))

要详细了解spec 的确切含义,请查看文档中的patch 部分。

作为最后一点,如果您有兴趣探索pytest 的伟大世界,可以创建一个pytest-elasticsearch 插件来帮助解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-27
    • 2018-09-26
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    相关资源
    最近更新 更多