python:模拟一个模块

时间:2014-05-28 00:02:19

标签: python mocking

是否可以使用unittest.mock在python中模拟模块?我有一个名为config的模块,在运行测试时我想用另一个模块test_config来模拟它。我怎样才能做到这一点 ?感谢。

config.py:

CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"

test_config.py:

CONF_VAR1 = "test_VAR1"
CONF_VAR2 = "test_VAR2" 

所有其他模块从config模块读取配置变量。在运行测试时,我希望他们从test_config模块中读取配置变量。

5 个答案:

答案 0 :(得分:7)

如果您一直在访问config.py中的变量,请执行以下操作:

import config
...
config.VAR1

您可以替换您实际尝试测试的模块导入的config模块。因此,如果您正在测试名为foo的模块,并导入并使用config,则可以说:

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

但实际上并没有全局替换模块,它只是在foo模块的命名空间中替换它。因此,您需要在导入的任何位置对其进行修补。如果foo执行此操作而不是import config

,它也无效
from config import VAR1

您还可以使用sys.modules来执行此操作:

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

但一般来说,混淆sys.modules不是一个好主意,我不认为这种情况有任何不同。我赞成所有其他建议。

答案 1 :(得分:5)

<强> 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')

如您所见,该补丁甚至适用于import foo期间执行的代码。

答案 2 :(得分:1)

如果您的申请(&#34; app.py&#34;说)看起来像

import config
print config.var1, config.var2

并提供输出:

$ python app.py
VAR1 VAR2

您可以使用mock.patch修补各个配置变量:

from mock import patch

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

这导致:

$ python mockimport.py
test_VAR1 VAR2

虽然我不确定这是否可以在模块级别进行。

答案 3 :(得分:1)

如果您想模拟整个模块,只需模拟使用该模块的导入即可。

for (i = 0; i < $("li").length; i++) { // Get the initial text of every list item let initialText = $("li").eq(i).attr("class"); // Remove the whitespace and convert to lower case let newText = initialText.replace(/ /g, "").toLowerCase(); // Set the list item class to the new text $("li").eq(i).attr("class", newText); }

myfile.py

import urllib

test_myfile.py

答案 4 :(得分:0)

考虑以下设置

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

现在您可以使用代码中的其他地方:

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

当你想模拟你的配置文件时,只需设置环境变量“TEST”。

额外信用: 如果您有许多在测试和非测试代码之间共享的配置变量,那么您可以从Config派生TestConfig并简单地覆盖需要更改的变量:

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