【问题标题】:How can i mock configparser.ConfigParser read method in python我如何在 python 中模拟 configparser.ConfigParser 读取方法
【发布时间】:2021-08-20 15:40:48
【问题描述】:

我正在使用 python 并且是新手。我正在尝试为我的类方法编写单元测试,我们使用 configparse 来获取位于特定路径的配置文件详细信息。

在进行单元测试时,它给我一个错误,因为 KeyError for

configparser 的代码是这样的

 algor_conf = configparser.ConfigParser()
 self.algor_conf.read('./path')
 self.algor_conf['DynamicProgramingParamaters']['wealth_state_total']

谁能帮我模拟一下这个

【问题讨论】:

    标签: python python-3.x unit-testing mocking pytest


    【解决方案1】:

    这里有一些解决方案。随意选择最适合您需求的 6 个(命名为 test_mock1test_mock6)。

    src.py

    import configparser
    
    
    class MyClass:
        def my_method(self):
            self.algor_conf = configparser.ConfigParser()
            self.algor_conf.read('./path')
            return self.algor_conf['DynamicProgramingParamaters']['wealth_state_total']
    

    test_src.py

    import configparser
    from unittest.mock import patch
    
    import pytest
    
    from src import MyClass
    
    
    def custom_get_item(key):
        if key == 'DynamicProgramingParamaters':
            return {'wealth_state_total': 'Just a test 3!'}
        else:
            raise KeyError(str(key))
    
    
    class CustomConfigParser1(configparser.ConfigParser):
        def __getitem__(self, key):
            if key == 'DynamicProgramingParamaters':
                return {'wealth_state_total': 'Just a test 4!'}
            else:
                raise KeyError(str(key))
    
    
    class CustomConfigParser2(configparser.ConfigParser):
        def read(self, filenames, *args, **kwargs):
            # Intercept the calls to configparser -> read and replace it to read from your test data
            if './path' == filenames:
                # Option 1: If you want to manually write the configuration here
                self.read_string("[DynamicProgramingParamaters]\nwealth_state_total = Just a test 5!")
    
                # Option 2: If you have a test configuration file
                # super().read("./test_path")
            else:
                super().read(filenames, *args, **kwargs)
    
    
    
    @pytest.fixture
    def amend_read(mocker):  # Requires https://pypi.org/project/pytest-mock/ but you can also change this to just use the builtin unittest.mock
        original_func = configparser.ConfigParser.read
    
        def updated_func(self, filenames, *args, **kwargs):
            # Intercept the calls to configparser -> read and replace it to read from your test data
            if './path' == filenames:
                # Option 1: If you want to manually write the configuration here
                self.read_string("[DynamicProgramingParamaters]\nwealth_state_total = Just a test 6!")
    
                # Option 2: If you have a test configuration file
                # original_func.read(self, "./test_path")
    
                return
    
            return original_func(self, filenames, *args, **kwargs)
    
        mocker.patch('configparser.ConfigParser.read', new=updated_func)
    
    
    @patch('configparser.ConfigParser')
    def test_mock1(config_parser):
        # If you just want to mock the configparser without doing anything to its processing results
        obj = MyClass()
        result = obj.my_method()
        print(result)
    
    
    @patch('configparser.ConfigParser.__getitem__', return_value={'wealth_state_total': 'Just a test 2!'})
    def test_mock2(config_parser):
        # Change the returned value of configparser['DynamicProgramingParamaters']['wealth_state_total']
        obj = MyClass()
        result = obj.my_method()
        print(result)
    
    
    @patch('configparser.ConfigParser.__getitem__', side_effect=custom_get_item)
    def test_mock3(config_parser):
        # Same as test_mock2 only that we instead used a function to write the return
        obj = MyClass()
        result = obj.my_method()
        print(result)
    
    
    @patch('configparser.ConfigParser', side_effect=CustomConfigParser1)
    def test_mock4(config_parser):
        # Same as test_mock3 only that we instead used a class to write the return
        obj = MyClass()
        result = obj.my_method()
        print(result)
    
    
    @patch('configparser.ConfigParser', side_effect=CustomConfigParser2)
    def test_mock5(config_parser):
        # If have a configuration file for your test data, use this.
        obj = MyClass()
        result = obj.my_method()
        print(result)
    
    
    def test_mock6(amend_read):
        # Same as test_mock5 only that we instead used a function to write the return
        obj = MyClass()
        result = obj.my_method()
        print(result)
    

    输出

    $ pytest -rP
    test_mock.py ......                                                                                                                                                                      [100%]
    
    ============================================================================================ PASSES ============================================================================================
    __________________________________________________________________________________________ test_mock1 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    <MagicMock name='ConfigParser().__getitem__().__getitem__()' id='140151691208160'>
    __________________________________________________________________________________________ test_mock2 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    Just a test 2!
    __________________________________________________________________________________________ test_mock3 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    Just a test 3!
    __________________________________________________________________________________________ test_mock4 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    Just a test 4!
    __________________________________________________________________________________________ test_mock5 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    Just a test 5!
    __________________________________________________________________________________________ test_mock6 __________________________________________________________________________________________
    ------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------
    Just a test 6!
    ====================================================================================== 6 passed in 0.03s =======================================================================================
    

    【讨论】:

      猜你喜欢
      • 2015-08-23
      • 2019-02-16
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      • 2011-10-06
      • 2013-09-12
      • 2022-09-28
      相关资源
      最近更新 更多