python: mock a module

后端 未结 4 1076
故里飘歌
故里飘歌 2020-12-03 11:09

Is it possible to mock a module in python using unittest.mock? I have a module named config, while running tests I want to mock it by another modul

相关标签:
4条回答
  • 2020-12-03 11:38

    foo.py:

    import config
    
    VAR1 = config.CONF_VAR1
    
    def bar():
        return VAR1
    

    test.py:

    import unittest
    import unittest.mock as mock
    
    import test_config
    
    
    class Test(unittest.TestCase):
    
        def test_one(self):
            with mock.patch.dict('sys.modules', config=test_config):
                import foo
                self.assertEqual(foo.bar(), 'test_VAR1')
    

    As you can see, the patch works even for code executed during import foo.

    0 讨论(0)
  • 2020-12-03 11:40

    Consider this following setup

    configuration.py:

    import os
    
    class Config(object):
        CONF_VAR1 = "VAR1"
        CONF_VAR2 = "VAR2"
    
    class TestConfig(object):
        CONF_VAR1 = "test_VAR1"
        CONF_VAR2 = "test_VAR2"
    
    
    if os.getenv("TEST"):
        config = TestConfig
    else:
        config = Config
    

    now everywhere else in your code you can use:

    from configuration import config
    print config.CONF_VAR1, config.CONF_VAR2
    

    And when you want to mock your coniguration file just set the environment variable "TEST".

    Extra credit: If you have lots of configuration variables that are shared between your testing and non-testing code, then you can derive TestConfig from Config and simply overwrite the variables that need changing:

    class Config(object):
        CONF_VAR1 = "VAR1"
        CONF_VAR2 = "VAR2"
        CONF_VAR3 = "VAR3"
    
    class TestConfig(Config):
        CONF_VAR2 = "test_VAR2"
        # CONF_VAR1, CONF_VAR3 remain unchanged
    
    0 讨论(0)
  • 2020-12-03 11:42

    If your application ("app.py" say) looks like

    import config
    print config.var1, config.var2
    

    And gives the output:

    $ python app.py
    VAR1 VAR2
    

    You can use mock.patch to patch the individual config variables:

    from mock import patch
    
    with patch('config.var1', 'test_VAR1'):
        import app
    

    This results in:

    $ python mockimport.py
    test_VAR1 VAR2
    

    Though I'm not sure if this is possible at the module level.

    0 讨论(0)
  • 2020-12-03 11:48

    If you're always accessing the variables in config.py like this:

    import config
    ...
    config.VAR1
    

    You can replace the config module imported by whatever module you're actually trying to test. So, if you're testing a module called foo, and it imports and uses config, you can say:

    from mock import patch
    import foo
    import config_test
    ....
    with patch('foo.config', new=config_test):
       foo.whatever()
    

    But this isn't actually replacing the module globally, it's only replacing it within the foo module's namespace. So you would need to patch it everywhere it's imported. It also wouldn't work if foo does this instead of import config:

    from config import VAR1
    

    You can also mess with sys.modules to do this:

    import config_test
    import sys
    sys.modules["config"] = config_test
    # import modules that uses "import config" here, and they'll actually get config_test
    

    But generally it's not a good idea to mess with sys.modules, and I don't think this case is any different. I would favor all of the other suggestions made over it.

    0 讨论(0)
提交回复
热议问题