模拟全局变量

时间:2016-07-12 18:08:15

标签: python unit-testing mocking patch

我一直在尝试为模块实施一些单元测试。名为 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'))

我已经看过许多例子,其中包括补丁'适用于方法和类,但不适用于变量。我不想修补方法 database.get 因为我可能会在以后使用不同的参数再次使用它,所以我需要一个不同的响应。

我在这里做错了什么?

4 个答案:

答案 0 :(得分:23)

试试这个:

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

您需要在各个测试实际运行时应用模拟,而不仅仅是setUp()。我们可以在setUp()创建模拟,稍后使用with ...上下文管理器将其应用。

答案 1 :(得分:14)

可以对变量进行如下修补:

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

答案 2 :(得分:3)

您不需要使用模拟。只需导入模块并在setUp()

中更改全局值
import alphabet

class TestAlphabet(unittest.TestCase): 
   def setUp(self):
        alphabet.letters = ['a', 'b', 'c']

答案 3 :(得分:1)

我遇到了一个问题,我试图模拟在任何函数或类之外使用的变量,这是有问题的,因为它们在您尝试模拟类时使用,然后才能模拟值。< / p>

我最终使用了一个环境变量。如果环境变量存在,请使用该值,否则使用应用程序默认值。这样我就可以在我的测试中设置环境变量值。

在我的测试中,我在导入类之前有了这段代码

os.environ["PROFILER_LOG_PATH"] = "./"

在我班上:

log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH)

默认情况下,我的config.LOG_PATH/var/log/<my app name>,但现在测试运行时,日志路径将设置为当前目录。这样您就不需要root访问权来运行测试。