如何为单元测试打补丁Python的raise(或return)关键字?

时间:2019-07-01 16:15:14

标签: python unit-testing mocking pytest pytest-mock

mock.patch能够捕获的Python关键字的命名空间是什么?

当某人想打补丁打开或打印时,可以使用mock.patch("builtins.open")mock.patch("mymodule.open"),但这是不起作用的,例如,对于raise

如果我有raise somemodule.SomeException语句,那么我可以很容易地测试是否引发了异常,但是如何断言实际上引发了关键字关键字。喜欢(在pytestpytest-mock的帮助下):

def test_myfunction_calls_raise(self, mocker):
    mocked = mocker.patch("mymodule.raise")
    mymodule.myfunction()
    mocked.assert_called_once()

编辑:我有a very nice answer,所以模拟。补丁不适用。除此之外,除了显而易见的解决方案(测试结果)之外,还有其他有意义的技术可以测试代码中是否已调用Python关键字(raisereturn,...)?

编辑2: 我要测试的实际代码(pynput的Listener stop()在Xfce中无法正常工作,因此我必须引发异常以停止Listener线程):

import pynput
# ...

def stop(self):
    """Stops listener by raising an exception."""
    try:
        raise pynput.mouse.Listener.StopException
    except pynput.mouse.Listener.StopException:
        return False

编辑3:以上方法已通过以下两种测试方法进行了单元测试:

def test_stop_stops_listener(self, mocker):
    """StopException is raised if MagicMock has got StopException attribute."""
    mocked = mocker.patch("pynput.mouse.Listener")
    with pytest.raises(TypeError):  # catching classes that do not inherit from BaseException is not allowed
        base.BaseMouse().stop()
    assert hasattr(mocked, "StopException")

def test_stop_returns_False(self, mocker):
    assert base.BaseMouse().stop() is False

1 个答案:

答案 0 :(得分:2)

您无法修补关键字。它们是Python语法的一部分。当Python解释器获取一段Python代码时,它将对其进行解析并将其分几步转换为某种内部表示形式(“字节码”)。但是,字节码不再与原始源代码直接相关,而是“消失了”。

相反,模块和类属性以及它们在代码中的访问仍将在字节码中找到。修补基本上是这些属性的临时替换。

或者换句话说,您可以修补属性,但关键字不是属性。