Kév*_*rré 8 python unit-testing patch constants mocking
我试图了解使用ock.patch在Python中修补常量的不同方法。我的目标是能够使用Test类中定义的变量作为常量的修补值。
我发现了这个问题,该问题解释了如何修补常量: 如何在python中修补常量, 并且这个问题解释了如何在patch中 使用self:在python中使用self @patch decorator
但是从第二个链接,我无法获得testTwo方法(将模拟作为函数参数提供)
这是我的简化用例:
mymodule.py
MY_CONSTANT = 5
def get_constant():
return MY_CONSTANT
Run Code Online (Sandbox Code Playgroud)
test_mymodule.py
import unittest
from unittest.mock import patch
import mymodule
class Test(unittest.TestCase):
#This works
@patch("mymodule.MY_CONSTANT", 3)
def test_get_constant_1(self):
self.assertEqual(mymodule.get_constant(), 3)
#This also works
def test_get_constant_2(self):
with patch("mymodule.MY_CONSTANT", 3):
self.assertEqual(mymodule.get_constant(), 3)
#But this doesn't
@patch("mymodule.MY_CONSTANT")
def test_get_constant_3(self, mock_MY_CONSTANT):
mock_MY_CONSTANT.return_value = 3
self.assertEqual(mymodule.get_constant(), 3)
#AssertionError: <MagicMock name='MY_CONSTANT' id='64980808'> != 3
Run Code Online (Sandbox Code Playgroud)
我的猜测是我不应该使用return_value,因为mock_MY_CONSTANT不是函数。那么我应该使用什么属性来替换调用常量时返回的值?
我认为您正在尝试了解单元测试、模拟对象以及如何替换被测代码中的常量值。
我将从您关于修补常量的具体问题开始,然后我将描述一种更通用的替换常量值的方法。
您的具体问题是关于之间的差异patch("mymodule.MY_CONSTANT", 3)和patch("mymodule.MY_CONSTANT")。根据docs,第二个参数是new,它包含将被修补的替换值。如果将其保留为默认值,则将MagicMock修补一个对象。正如您在问题中指出的那样,MagicMock.return_value适用于函数,但您没有调用MY_CONSTANT,因此永远不会使用返回值。
我对这个问题的简短回答是,“不要MagicMock用来替换常量。” 如果出于某种原因,您非常想这样做,您可以覆盖您在该常量上调用的唯一内容,即它的__eq__()方法。(我想不出任何情况下这是一个好主意。)
import unittest
from unittest.mock import patch
import mymodule
class Test(unittest.TestCase):
#This works
@patch("mymodule.MY_CONSTANT", 3)
def test_get_constant_1(self):
self.assertEqual(mymodule.get_constant(), 3)
#This also works
def test_get_constant_2(self):
with patch("mymodule.MY_CONSTANT", 3):
self.assertEqual(mymodule.get_constant(), 3)
#This now "works", but it's a horrible idea!
@patch("mymodule.MY_CONSTANT")
def test_get_constant_3(self, mock_MY_CONSTANT):
mock_MY_CONSTANT.__eq__ = lambda self, other: other == 3
self.assertEqual(mymodule.get_constant(), 3)
Run Code Online (Sandbox Code Playgroud)
现在是更一般的问题。我认为最简单的方法不是改变常量,而是提供一种覆盖常量的方法。改变常数对我来说是错误的,因为它被称为常数。(当然,这只是一个约定,因为 Python 不强制执行常量值。)
以下是我将如何处理您正在尝试做的事情。
MY_CONSTANT = 5
def get_constant(override=MY_CONSTANT):
return override
Run Code Online (Sandbox Code Playgroud)
然后您的常规代码可以只调用get_constant(),而您的测试代码可以提供覆盖。
import unittest
import mymodule
class Test(unittest.TestCase):
def test_get_constant(self):
self.assertEqual(mymodule.get_constant(override=3), 3)
Run Code Online (Sandbox Code Playgroud)
随着您的代码变得更加复杂,这会变得更加痛苦。如果您必须通过一堆图层传递该覆盖,那么它可能不值得。但是,这可能表明您的设计存在问题,使代码更难测试。