如何对subprocess.CalledProcessError进行单元测试

时间:2017-08-09 01:54:09

标签: python-3.x unit-testing mocking pytest python-unittest

我有一个使用subprocess.check_output命令的脚本。在某些情况下,此命令可能会失败并引发subprocess.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:不允许捕获不从BaseException继承的类

如果我发表评论except subprocess.CalledProcessError as cpe:并取消注释#except Exception as cpe:,则测试会通过ouptut传递:

  

test.py
  错误类型:< class' subprocess.CalledProcessError'>
  ()

这似乎告诉我,错误是在mock和catch中指定的,并且执行了异常块。那么问题是,为什么在捕捉subprocess.CalledProcessError时它不起作用。

这会返回True

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

此时我猜测在整个过程中我遗漏了一些东西。

我错过了什么?

1 个答案:

答案 0 :(得分:1)

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

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

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