2015-07-11 19 views
0

我们有呼叫者可以用它来运行Mac OS X上的一些工具命令路径命令及其使用一个Python模块的操作系统版本之间的不同,我们的模块旨在隐藏用户。我们判断OS版本,一旦当模块被导入,就像这样(helper.py,简化演示点):测试支路在Python

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 ... 

现在我们想测试增加了这个模块。具体来说,我们想确保正确的实用程序运行为OS X的所有版本,我们正在运行的正确工具我想的是patchplatform.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。当test_10_9_utility_is_correct运行helper不被再次进口的,所以因为它认为这是在10.10失败。

我明白Python并不导入模块的两倍,这是真棒。但这是否意味着我们不能在测试中使用模块级代码执行分支,因为它只会运行一次?如果有办法这样做,怎么样?

我认为包装模块级的操作系统版本在功能校验码。这可以很容易地模拟,但其他所有函数都必须首先调用它,这似乎没有必要,因为操作系统版本在调用之间不可能发生变化。我也考虑过将每种测试方法移入自己的测试模块,这会导致多次导入helper,但这看起来很笨重。是否有另一种方式来练习helper.py中给出的两个分支?

回答

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() 
+0

谢谢你,这很好地工作。在任何测试之前运行的'init_module()'这个特定的例子并不算太坏,因为它只是捕获操作系统版本。但是现在我很好奇:有没有办法阻止它在导入到测试模块时运行?例如,如果代码中存在多个通常希望运行的副作用,但是在单元测试之前没有? –

+0

你可以,但我认为需要更多的工作。例如,你可以有一个布尔标志,告诉模块是否被初始化。对于模块的每个功能,如果该标志没有设置,它会调用init_module函数(设置该标志)。这样你只需要时就可以初始化它。但是您必须确保模块中的所有功能都执行此基本检查,这可能不值得。 – Patrick