模拟全局变量
Mocking a global variable
我一直在尝试为模块实施一些单元测试。名为alphabet.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
我想用我选择的一些值模拟来自数据库的响应,但下面的代码似乎不起作用。
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'))
我见过很多例子,其中 'patch' 应用于方法而 类,但不应用于变量。我不想修补方法 database.get 因为我以后可能会用不同的参数再次使用它,所以我需要不同的响应。
我做错了什么?
您不需要使用模拟。只需导入模块并在 setUp()
:
内更改全局值
import alphabet
class TestAlphabet(unittest.TestCase):
def setUp(self):
alphabet.letters = ['a', 'b', 'c']
试试这个:
import unittests
import alphabet
from unittest import mock
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'))
您需要应用模拟,而个别测试实际上是 运行,而不仅仅是 setUp()
。我们可以 在 setUp()
中创建 模拟,稍后使用 with ...
上下文管理器应用它。
我 运行 遇到一个问题,我试图模拟在任何函数或 class 之外使用的变量,这是有问题的,因为它们在您尝试模拟class,然后才能模拟这些值。
我最终使用了环境变量。如果环境变量存在,则使用该值,否则使用应用程序默认值。这样我就可以在我的测试中设置环境变量值。
在我的测试中,我在导入 class 之前有这段代码
os.environ["PROFILER_LOG_PATH"] = "./"
在我的 class:
log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH)
默认我的config.LOG_PATH
是/var/log/<my app name>
,但是现在测试的时候是运行ning,日志路径设置为当前目录。这样你就不需要 root 访问 运行 测试。
变量可以按如下方式修补:
from mock import patch
@patch('module.variable', new_value)
例如:
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')
如果您正在使用 pytest-mock
(参见 https://pypi.org/project/pytest-mock/),那么您需要做的就是使用内置夹具。
def test_my_function(mocker):
# Mock the value of global variable `MY_NUMBER` as 10
mocker.patch("path.to.file.MY_NUMBER", 10)
# rest of test...
我一直在尝试为模块实施一些单元测试。名为alphabet.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
我想用我选择的一些值模拟来自数据库的响应,但下面的代码似乎不起作用。
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'))
我见过很多例子,其中 'patch' 应用于方法而 类,但不应用于变量。我不想修补方法 database.get 因为我以后可能会用不同的参数再次使用它,所以我需要不同的响应。
我做错了什么?
您不需要使用模拟。只需导入模块并在 setUp()
:
import alphabet
class TestAlphabet(unittest.TestCase):
def setUp(self):
alphabet.letters = ['a', 'b', 'c']
试试这个:
import unittests
import alphabet
from unittest import mock
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'))
您需要应用模拟,而个别测试实际上是 运行,而不仅仅是 setUp()
。我们可以 在 setUp()
中创建 模拟,稍后使用 with ...
上下文管理器应用它。
我 运行 遇到一个问题,我试图模拟在任何函数或 class 之外使用的变量,这是有问题的,因为它们在您尝试模拟class,然后才能模拟这些值。
我最终使用了环境变量。如果环境变量存在,则使用该值,否则使用应用程序默认值。这样我就可以在我的测试中设置环境变量值。
在我的测试中,我在导入 class 之前有这段代码
os.environ["PROFILER_LOG_PATH"] = "./"
在我的 class:
log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH)
默认我的config.LOG_PATH
是/var/log/<my app name>
,但是现在测试的时候是运行ning,日志路径设置为当前目录。这样你就不需要 root 访问 运行 测试。
变量可以按如下方式修补:
from mock import patch
@patch('module.variable', new_value)
例如:
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')
如果您正在使用 pytest-mock
(参见 https://pypi.org/project/pytest-mock/),那么您需要做的就是使用内置夹具。
def test_my_function(mocker):
# Mock the value of global variable `MY_NUMBER` as 10
mocker.patch("path.to.file.MY_NUMBER", 10)
# rest of test...