代码之家  ›  专栏  ›  技术社区  ›  Ben

如何用pytest模拟导入的模块

  •  1
  • Ben  · 技术社区  · 7 年前

    以前也有人问过类似的问题,但我一直在努力让它发挥作用。

    如何从另一个文件模拟导入模块

    我有一个文件:
    b.py (命名与链接文档一致)

    import cv2   # module 'a' in the linked docs
    
    def get_video_frame(path):
        vidcap = cv2.VideoCapture(path)  # `a.SomeClass` in the linked docs
        vidcap.isOpened()
        ...
    

    测试结果

    import b
    import pytest # with pytest-mock installed
    
    def test_get_frame(mocker):
    
        mock_vidcap = mocker.Mock()
        mock_vidcap.isOpened.side_effect = AssertionError
    
        mock_cv2 = mocker.patch('cv2.VideoCapture')
        mock_cv2.return_value = mock_vidcap
    
        b.get_video_frame('foo')    # Doesn't fail
    
        mock_vidcap.isOpened.assert_called()   # fails
    

    我这样设置测试是因为 where to patch 它规定如果

    在这种情况下,我们要修补的类是在A模块上查找的,因此我们必须修补A.someClass:

    @patch(‘a.SomeClass’)
    

    我尝试过其他几种修补组合,但它表现出相同的行为,这表明我没有成功地修补模块。如果要应用补丁 b.get_video_frame('foo') 会因为 side_effect ;有 assert_called 失败,支持这个。

    编辑 为了缩短问题的长度,我把剩下的 get_video_frame . 不可否认,剩下的部分我们是关键部分。全部功能是:

    def get_video_frame(path):
        vidcap = cv2.VideoCapture(path)  # `a.SomeClass` in the linked docs
        is_open = vidcap.isOpened()
        while True:
            is_open, frame = vidcap.read()
            if is_open:
                yield frame
            else:
                break
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   wim    7 年前

    这一行只创建了一个生成器:

    b.get_video_frame('foo')
    

    这条线 is_open = vidcap.isOpened() 从未达到,因为在测试功能中,发电机在启动时保持冻结状态,因此副作用从未升高。

    否则,您将正确使用mocker和patch。