Python 模拟全局变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38336090/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mocking a global variable
提问by Funkatic
I've been trying to implement some unit tests for a module. An example module named alphabet.pyis as follows:
我一直在尝试为一个模块实现一些单元测试。一个名为字母表.py的示例模块如下:
import database
def length_letters():
return len(letters)
def contains_letter(letter):
return True if letter in letters else False
letters = database.get('letters') # returns a list of letters
I'd like to mock the response from a database with some values of my choice, but the code below doesn't seem to work.
我想用我选择的一些值来模拟来自数据库的响应,但下面的代码似乎不起作用。
import unittests
import alphabet
from unittest.mock import patch
class TestAlphabet(unittest.TestCase):
@patch('alphabet.letters')
def setUp(self, mock_letters):
mock_letters.return_value = ['a', 'b', 'c']
def test_length_letters(self):
self.assertEqual(3, alphabet.length_letters())
def test_contains_letter(self):
self.assertTrue(alphabet.contains_letter('a'))
I have seen many examples in which 'patch' is applied to methods and classes, but not to variables. I prefer not to patch the method database.getbecause I may use it again with different parameters later on, so I would need a different response.
我见过很多例子,其中“补丁”应用于方法和类,但不适用于变量。我不想修补方法database.get因为我以后可能会用不同的参数再次使用它,所以我需要不同的响应。
What am I doing wrong here?
我在这里做错了什么?
回答by Valera Maniuk
Variables can be patched as follows:
可以按如下方式修补变量:
from mock import patch
@patch('module.variable', new_value)
For example:
例如:
import alphabet
from mock import patch
@patch('alphabet.letters', ['a', 'b', 'c'])
class TestAlphabet():
def test_length_letters(self):
assert 3 == alphabet.length_letters()
def test_contains_letter(self):
assert alphabet.contains_letter('a')
回答by Will
Try this:
尝试这个:
import unittests
import alphabet
from unittest.mock import patch
class TestAlphabet(unittest.TestCase):
def setUp(self):
self.mock_letters = mock.patch.object(
alphabet, 'letters', return_value=['a', 'b', 'c']
)
def test_length_letters(self):
with self.mock_letters:
self.assertEqual(3, alphabet.length_letters())
def test_contains_letter(self):
with self.mock_letters:
self.assertTrue(alphabet.contains_letter('a'))
You need to apply the mock while the individual tests are actually running, not just in setUp()
. We can createthe mock in setUp()
, and apply it later with a with ...
Context Manager.
您需要在单个测试实际运行时应用模拟,而不仅仅是在setUp()
. 我们可以在 中创建模拟setUp()
,然后在with ...
上下文管理器中应用它。
回答by John Gordon
You don't need to use mock. Just import the module and alter the value of the global within setUp()
:
你不需要使用模拟。只需导入模块并更改其中的全局值setUp()
:
import alphabet
class TestAlphabet(unittest.TestCase):
def setUp(self):
alphabet.letters = ['a', 'b', 'c']
回答by Ruth Grace Wong
I ran into a problem where I was trying to mock out variables that were used outside of any function or class, which is problematic because they are used the moment you try to mock the class, before you can mock the values.
我遇到了一个问题,我试图模拟在任何函数或类之外使用的变量,这是有问题的,因为它们在您尝试模拟类的那一刻被使用,然后才能模拟值。
I ended up using an environment variable. If the environment variable exists, use that value, otherwise use the application default. This way I could set the environment variable value in my tests.
我最终使用了一个环境变量。如果环境变量存在,则使用该值,否则使用应用程序默认值。这样我就可以在我的测试中设置环境变量值。
In my test, I had this code before the class was imported
在我的测试中,我在导入类之前有这个代码
os.environ["PROFILER_LOG_PATH"] = "./"
In my class:
在我的课堂上:
log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH)
By default my config.LOG_PATH
is /var/log/<my app name>
, but now when the test is running, the log path is set to the current directory. This way you don't need root access to run the tests.
默认情况下 myconfig.LOG_PATH
是/var/log/<my app name>
,但现在当测试运行时,日志路径设置为当前目录。这样您就不需要 root 访问权限来运行测试。