在python中测试模块级代码中的分支

时间:2015-07-11 19:40:15

标签: python unit-testing mocking monkeypatching

我们有一个python模块,调用者可以使用它来在Mac OS X上运行一些实用程序命令。命令的路径及其用法因操作系统版本而异,我们的模块旨在将其隐藏起来。我们在导入模块时确定一次操作系统的版本,就像这样(import platform from distutils.version import StrictVersion print('Importing helper module...') os_version, _, _ = platform.mac_ver() if StrictVersion(os_version) < StrictVersion('10.10'): utility1 = 'utility 1 for 10.9 and below' else: utility1 = 'utility 1 for 10.10 and above' def run_utility1(): return 'Running ' + utility1 def run_utility2(): # ... pass # ... more cool functions ... ,简化以证明这一点):

patch

现在我们要为此模块添加测试。具体来说,我们要确保为所有版本的OS X运行正确的实用程序。我想到的方法是在不同的测试中platform.mac_ver() assert返回不同的操作系统版本,和import mock import unittest class HelperTests(unittest.TestCase): def test_10_9_utility_is_correct(self): with mock.patch('platform.mac_ver', return_value=('10.9', 'foo', 'foo')): import helper result = helper.run_utility1() print(result) assert result == 'Running utility 1 for 10.9 and below' def test_10_10_utility_is_correct(self): with mock.patch('platform.mac_ver', return_value=('10.10', 'foo', 'foo')): import helper result = helper.run_utility1() print(result) assert result == 'Running utility 1 for 10.10 and above' if __name__ == '__main__': unittest.main() 我们正在运行正确的实用程序。像这样:

Testing started at 12:16 PM ...
Importing helper module...
Running utility 1 for 10.10 and above
Running utility 1 for 10.10 and above

Process finished with exit code 0

Failure
Traceback (most recent call last):
  File "helper_test.py", line 13, in test_10_9_utility_is_correct
    assert result == 'Running utility 1 for 10.9 and below'
AssertionError

但结果是:

test_10_10_utility_is_correct

似乎mac_ver()首先运行(这是由于测试工具中方法的字母排序吗?),修补10.10以返回helper然后导入{{1} }。当test_10_9_utility_is_correct运行时helper没有再次导入,因此它会失败,因为它认为它在10.10上。

据我所知,python没有两次导入模块,而且非常棒。但这是否意味着我们不能在测试中的模块级代码中运行分支,因为它只会运行一次?如果有办法,怎么做?

我考虑过在函数中包装模块级操作系统版本检查代码。这将使模拟变得容易,但是所有其他函数必须首先调用它,这似乎是不必要的,因为操作系统版本不可能在调用之间改变。我还考虑过将每个测试方法移动到自己的测试模块中,这会导致helper多次导入,但这看起来非常笨重。是否有另一种方法来行使helper.py中给出的两个分支?

1 个答案:

答案 0 :(得分:0)

如何将初始化代码放入函数中?

你必须像这样声明你的全局变量:

import platform
from distutils.version import StrictVersion

utility1 = None
def init_module():
    global utility1 # declare it global to modify it
    print('Importing helper module...')

    os_version, _, _ = platform.mac_ver()

    if StrictVersion(os_version) < StrictVersion('10.10'):
        utility1 = 'utility 1 for 10.9 and below'
    else:
        utility1 = 'utility 1 for 10.10 and above'

init_module() #Call the init function when importing the module

def run_utility1():
    return 'Running ' + utility1

然后在每个新测试中,您可以调用init函数:

import mock
import unittest
import helper

class HelperTests(unittest.TestCase):
    def test_10_9_utility_is_correct(self):
        with mock.patch('platform.mac_ver', return_value=('10.9', 'foo', 'foo')):
            helper.init_module()
            result = helper.run_utility1()
            print(result)
            assert result == 'Running utility 1 for 10.9 and below'

    def test_10_10_utility_is_correct(self):
        with mock.patch('platform.mac_ver', return_value=('10.10', 'foo', 'foo')):
            helper.init_module()
            result = helper.run_utility1()
            print(result)
            assert result == 'Running utility 1 for 10.10 and above'

if __name__ == '__main__':
    unittest.main()