在 unittest 中模拟库(在 Python 3.7 中)

时间:2021-02-11 00:13:08

标签: python mocking python-unittest

我有一个使用 elasticsearch 的类,我正在尝试为它编写单元测试。

from elasticsearch import Elasticsearch

class MyClass:
    def __init__(self):
        # ...
        self.client = Elasticsearch(connection)  # Connect to ES

    def get_mapping(self):
        mapping = self.client.indices.get_mapping(
            index=self.index_name
        )
        # ... extra code that simplifies mapping
        return mapping

这是我在单元测试中的内容:

from myproject.module.submodule import MyClass

class MyTestCase(unittest.TestCase):  # pragma: no cover, duplicates expected

    def setUp(self):
        patcher = mock.patch('elasticsearch.Elasticsearch')
        self.mock_es = patcher.start()
        self.addCleanup(patcher.stop)

    def test_mapping(self):
        self.mock_es.indices.get_mapping.return_value = {
            "some_index": {
                "mappings": {
                    "properties": {
                        "field_one": {
                            "type": "text",
                        },
                        "field_two": {
                            "type": "text",
                        }
                    }
                }
            }
        }

        mapping = MyClass().get_mapping()
        expected_mapping = {
            "some_index": {
                "field_one": "text",
                "field_two": "text",
            }
        }

        self.assertEqual(mapping, expected_mapping)

我的期望是,在运行单元测试时,实际 elasticsearch 库不应该被使用。

但是,当我运行上面的代码时,它会尝试连接到 elasticsearch。

我做错了什么?

1 个答案:

答案 0 :(得分:0)

我想通了。需要进行两项更改:

  1. 在 setUp() 中,我需要修补 elasticsearch.Elasticsearch 而不是修补 myproject.module.submodule.Elasticsearch

    评论中提到了这一点。

  2. 代替 self.mock_es.indices.get_mapping.return_value = <some_value> 应该是:

     instance = self.mock_es.return_value
     instance.indices.get_mapping.return_value = <some_value>
    

    在模拟一个类之后,为了能够模拟一个方法的返回值,需要模拟每个实例,而不是类方法。

所以最后的测试类是:

class MyTestCase(unittest.TestCase):  # pragma: no cover, duplicates expected

    def setUp(self):
        patcher = mock.patch('myproject.module.submodule.Elasticsearch')
        self.mock_es = patcher.start()
        self.addCleanup(patcher.stop)

    def test_mapping(self):
        instance = self.mock_es.return_value
        instance.indices.get_mapping.return_value = {
            "some_index": {
                "mappings": {
                    "properties": {
                        "field_one": {
                            "type": "text",
                        },
                        "field_two": {
                            "type": "text",
                        }
                    }
                }
            }
        }

        mapping = MyClass().get_mapping()
        expected_mapping = {
            "some_index": {
                "field_one": "text",
                "field_two": "text",
            }
        }

        self.assertEqual(mapping, expected_mapping)
相关问题