【问题标题】:How to intercept function call and change parameters with pytest?如何使用pytest拦截函数调用和更改参数?
【发布时间】:2017-06-23 10:58:30
【问题描述】:

假设有一个函数download_page_html(url) 下载(有效)url 指向的页面的 HTML 内容。各种功能使用它download_page_html 来完成他们的工作。

现在,在测试时,我不想从 Wikipedia 而是从 localhost 下载 HTML。

那么如何拦截各种函数对download_page_html的调用并替换url参数的值呢?

【问题讨论】:

    标签: python-3.x testing mocking tdd pytest


    【解决方案1】:

    使用 Python 的 stdlib unittest.mock.patch - 它既可以用作装饰器,也可以用作上下文管理器(即使用 with 语句)。

    如果您传入 new 关键字参数,则该函数将被压缩到那个位置 - 您只需放置一个调用原始函数的单行代码 您选择的参数:

    from unittest.mock import patch
    
    from mymodule import download_page_html as original_download_page
    
    @patch('mymodule.download_page_html', new=lambda page: original_download_page("http://localhost/page.html"))
    def test_my_test_function(...):
        ...
    

    【讨论】:

    • 无需通过混合pytestunittest 来使事情复杂化。如果您已经在使用pytest,只需使用其内置的monkeypatch 工具即可。
    • 这并不复杂 - unittest.mock 被推荐并用于所有 pytest 文档。这只是愚蠢的“报复”。尽量客观。
    • 假设“pytest 文档”是指 pytest 文档(如果不是还有什么?),我建议您打开 pytest documentation page 并搜索 unittest.mockfrom unittest 或下载PDFdocumentation 并进行搜索。我发现使用unittest.mock 的结果为零。所以请用一些参考资料来支持你的主张或解释你认为是“pytest 文件”的内容
    【解决方案2】:

    您应该在“各种函数”中添加一个可选的dph=None 参数,然后在函数体中将其重新分配给硬编码的download_page_html 函数:

    def my_various_function(url, arg2, kw1=val1, dph=None):
        if dph is None:
            dph = download_page_html
        res = dph(url)
    

    如果您认为您的设计不值得进行此类更改,请使用pytest 的内置monkeypatch

    import pytest   # no need to import monkeypatch from pytest
    
    def test_mytest(monkeypatch):
        url = 'some_url'
        def mockdlpage(url):
            return 'the_mock_data'
        monkeypatch.setattr(yourmodule, 'download_page_html', mockdlpage)
        data = download_page_html(url)
    

    【讨论】:

    • 除非更改功能是系统的必要功能,否则这样做是一种非常糟糕的做法。您不应该仅仅为了能够对其进行测试而使代码复杂化。
    • 根据我的经验,使用硬编码的顶级函数的不灵活性是改变设计的必要基础。
    • 这种方法需要更改测试代码——这不是预期的。可能有一个正确的方法来使用monkeypatch,它不需要修改原始源代码。
    • @Anthon,只是好奇。在您的第二个示例中,download_page_html 函数是原始函数,而不是上面行中的修补函数?
    • @tudor 是正确且故意的。答案的第一部分是通过更改要测试的原始代码,通过一个“知道”如何处理您正在测试的情况的函数进行间接调用(并提交参数dph)。第二部分是当您不想这样做时,在这种情况下,您使用 pytest 提供的猴子补丁,就好像您调用 downloadpagehtml() 但实际上您将调用 mockdlpage() 因为猴子补丁
    猜你喜欢
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多