2017-08-09 216 views
0

我有一个使用命令subprocess.check_output的脚本。有些情况下,这个命令可能会失败并引发subprocess.CalledProcessError如何对子进程进行单元测试.CalledProcessError

我正在尝试为此函数编写一个单元测试(使用pytest来运行测试)并测试异常情况。

pytest 3.1.2
的Python 3.5.3

我写的代码,这个小位与无济于事探索。

# mytest.py 
import subprocess 

def test_sub(): 
    try: 
     command_output = subprocess.check_output("unzip x".split()) 
     # unzip x is used to raise the exception when running with python 
     # but would be replaced by proper command that may fail 
     output = command_output 
    except subprocess.CalledProcessError as cpe: 
    #except Exception as cpe: 
     print("\nType of error:", type(cpe)) 
     print(cpe.args) 
     output = "unzip" 
    return output 

if __name__ == '__main__': 
    print(test_sub()) 

python mytest.py运行输出unzip如预期的,因为unzip命令将失败,并引发错误。

这是测试功能

# test.py 
import unittest 
import unittest.mock as mock 
from mytest import test_sub 
import subprocess 

class SubErrorTest(unittest.TestCase): 

    @mock.patch('mytest.subprocess', autospec=True) 
    def test_subprocess_error_thrown(self, mock_subprocess): 

     mock_subprocess.check_output.side_effect = subprocess.CalledProcessError(returncode=2,cmd=["bad"]) 
     output = test_sub() 
     self.assertEqual("unzip", output) 

代码在运行时pytest test.py测试失败,错误

output = test_sub() #error thrown from here in test 

test.py:

def test_sub(): 
    try: 
     command_output = subprocess.check_output("unzip x".split()) 
     output = command_output 
except subprocess.CalledProcessError as cpe: #error is indicated here 

E TypeError: catching classes that do not inherit from BaseException is not allowed

如果我评论except subprocess.CalledProcessError as cpe:并取消#except Exception as cpe:测试通过与ouptut:

test.py
Type of error: <class 'subprocess.CalledProcessError'>
()

这似乎是建议让我明白错误是按照模拟中指定的方式抛出,并捕获异常块并执行。那么问题是,为什么在捕获subprocess.CalledProcessError时不起作用。

这将返回True

isinstance(subprocess.CalledProcessError(returncode=2,cmd=["bad"]), BaseException) 

在这一点上我猜,有我在整个过程中我失去了一些东西。

我错过了什么?

回答

1

我认为你正在修补错误的路径。

@mock.patch('mytest.subprocess', autospec=True) 

该路径应该是被测模块的路径而不是测试本身。我认为正在发生的是test.py命名空间中的模拟子进程,所以当您将side_effect设置为subprocess.CalledProcessError时,您将其设置为模拟。您可以在设置后记录side_effect来验证这一点。