为啥我的模拟对象不能识别对它的任何调用?

Posted

技术标签:

【中文标题】为啥我的模拟对象不能识别对它的任何调用?【英文标题】:Why does my mock object not recognize any calls to it?为什么我的模拟对象不能识别对它的任何调用? 【发布时间】:2017-10-03 04:15:48 【问题描述】:

这是一些单元测试,我已将其简化为重现问题的最小示例。

import unittest
import zipfile
from unittest.mock import patch

"""My 'production' function"""
def list_txt_in_zipfile(zip_file_path):
    with open(zip_file_path, "rb") as file:
        zf = zipfile.ZipFile(file)
        print("zipfile.ZipFile is", zipfile.ZipFile)
    return [f_name for f_name in zf.namelist() if f_name.endswith(".txt")]


class UnzipperTest(unittest.TestCase):

    """My test method"""
    @patch("__main__.zipfile.ZipFile")
    def test_list_txt_in_zipfile(self, mock_ZipFile):
        txt_list = list_txt_in_zipfile("my.txt.zip")
        mock_ZipFile.assert_any_call() # AssertionError
        print("mock_ZipFile is", mock_ZipFile)


if __name__ == '__main__':
    unittest.main()

断言错误:

AssertionError: ZipFile() call not found

当我的测试方法调用list_txt_in_zipfile 时,它会记录一个模拟对象,而不是真正的zipfile.Zipfile(来自Python 的zipfile.py)。

如果我在生产函数中打印这“两个”对象zipfile.ZipFile,在我的测试方法中打印mock_ZipFile,它们就是同一个对象:

zipfile.ZipFile is <MagicMock name='ZipFile' id='3069297420'>
mock_ZipFile is <MagicMock name='ZipFile' id='3069297420'>

为什么mock_ZipFile 无法断言对它的任何调用?

我实际上已经成功测试了 list_txt_in_zipfile 函数,方法是将其拆分为两个函数(open() 部分和 zipfile.ZipFile() 的其余部分,但就目前而言,这不是一个巨大的函数,所以我会喜欢把这段逻辑放在一个地方。

更新:测试方法中的my.txt.zip 确实存在,我没有设法引入unittest.mock.mock_open 来模拟open(),因为我一直在模拟zipfile.ZipFile

【问题讨论】:

【参考方案1】:

assert_any_call 断言已使用指定的参数调用模拟对象。您没有在断言中传递任何参数,但在函数本身中 zipfile.Zipfile() 使用一个参数调用,即文件对象。

【讨论】:

有效点。实际上,我很难找出将什么放入原始的 assert_call_once_with 中,所以我误认为 assert_any_call 是一个在没有特定参数列表的情况下传递的方法。 help() 还说 “如果模拟 *曾经* 被调用过,则断言通过,不像 assert_called_withassert_called_once_with 只有在调用是最近的调用时才会通过。” 再次与第一句一起,暗示“永远(使用指定的参数)”。如果您只想断言它已被调用,请使用assert_called() 再次感谢您。我已将unittest.mock.ANY 填入assert_any_call,现在它通过了。

以上是关于为啥我的模拟对象不能识别对它的任何调用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在调用它的析构函数后我可以访问这个堆栈分配的对象? [复制]

Java关键字

为啥“基类对象”不能调用它自己的虚函数? C++

为啥从内部类调用特定于对象的方法/字段时没有抛出任何错误?

为啥我不能在我的 ArrayList<T> 上调用 Collections.sort()?

为啥我的 watchkit 应用程序没有在“开始”状态调用我的平移手势识别器处理代码?