如何使用模拟作为函数参数修补Python中的常量

问题描述:

我想了解使用mock.patch修补Python中常量的不同方法。 我的目标是能够使用在我的测试类定义为我不断修补值的变量。如何使用模拟作为函数参数修补Python中的常量

我发现这个问题,这也解释了如何修补一个常数: How to patch a constant in python 而这个问题解释如何使用自己版本: using self in python @patch decorator

但是从这个第二个环节,我不能得到testTwo方式(提供模拟作为函数参数)工作

这里是我的简单的用例:

我module.py

MY_CONSTANT = 5 

def get_constant(): 
    return MY_CONSTANT 

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 

我的猜测是我shoudln't使用RETURN_VALUE,因为mock_MY_CONSTANT不是一个函数。那么我应该使用什么属性来替换常量被调用时返回的值呢?

可以的simpy每个断言之前分配的模拟值不变:

def test_get_constant_3(self): 
    mymodule.MY_CONSTANT = 3 
    self.assertEqual(mymodule.get_constant(), 3) 
    mymodule.MY_CONSTANT = 7 
    self.assertEqual(mymodule.get_constant(), 7) 

有些另一个例子

# --- config.py --- 

class AppConf: 
    APP_TIMEZONE = os.environ.get['APP_TIMEZONE'] 



# --- my_mod.py --- 

from datetime import datetime 
from config import AppConf 

LOCAL_TZ = AppConf.APP_TIMEZONE 

def to_local_tz(dt_obj, tz): 
    """Return datetime obj for specific timezone""" 
    # some code here 
    return local_dt_obj 

def get_local_time(): 
    return to_local_tz(datetime.utcnow(), LOCAL_TZ).strftime('%H:%M') 



# --- test_my_mod.py --- 

import my_mod 

class TestMyMod(unittest.TestCase): 
    @patch('my_mod.datetime') 
    def test_get_local_time(self, mock_dt): 
     # Mock to 15:00 UTC 
     mock_dt.utcnow.return_value = datetime(2017, 5, 3, 15) 

     # Test with TZ 'Europe/Kiev'  +02:00 +03:00(DST) 
     my_mod.LOCAL_TZ = 'Europe/Kiev' 
     assert my_mod.get_local_time() == '18:00' 

     # Test with TZ 'America/New_York' -05:00 -04:00(DST) 
     my_mod.LOCAL_TZ = 'America/New_York' 
     assert my_mod.get_local_time() == '11:00' 

所以没必要修补恒定在所有

+0

首先感谢回答我! 是但在这种情况下,这意味着mymodule.MY_CONSTANT的值更改为所有即将到来的测试。这就是为什么我想使用补丁,所以它仅限于我补丁的范围。 –

+0

然后在你的情况下使用'with patch():'。你还需要什么?无法理解问题,对不起。 –

+0

在变体#3中,无论如何您都会得到与#2相同的结果,为什么您需要类似#3格式的内容? –

要回答这个问题从理论上说,我想你会需要修补上,不断的__int__()方法,像这样:

@patch("mymodule.MY_CONSTANT.__int__") 
def test_get_constant_4(self, mock_MY_CONSTANT): 
    mock_MY_CONSTANT.return_value = 3 
    self.assertEqual(mymodule.get_constant(), 3) 

显然,这是错误的方式去了解它,如图它抛出的错误。

AttributeError: 'int' object attribute '__int__' is read-only