【问题标题】:Not able to mock urllib2.urlopen using Python's mock.patch无法使用 Python 的 mock.patch 模拟 urllib2.urlopen
【发布时间】:2015-06-04 14:16:17
【问题描述】:

下面是我的 api.py 模块的代码 sn-p

# -*- coding: utf-8 -*-

from urllib2 import urlopen
from urllib2 import Request

class API:

    def call_api(self, url, post_data=None, header=None):
        is_post_request = True if (post_data and header) else False
        response = None
        try:
            if is_post_request:
                url = Request(url = url, data = post_data, headers = header)
            # Calling api
            api_response = urlopen(url)
            response = api_response.read()
        except Exception as err:
            response = err

        return response

我试图在上述模块的unittest 中模拟urllib2.urlopen。我已经写了

# -*- coding: utf-8 -*-
# test_api.py

from unittest import TestCase
import mock

from api import API

class TestAPI(TestCase):

    @mock.patch('urllib2.Request')
    @mock.patch('urllib2.urlopen')
    def test_call_api(self, urlopen, Request):
        urlopen.read.return_value = 'mocked'
        Request.get_host.return_value = 'google.com'
        Request.type.return_value = 'https'
        Request.data = {}
        _api = API()
        assert _api.call_api('https://google.com') == 'mocked'

运行单元测试后,出现异常

<urlopen error unknown url type: <MagicMock name='Request().get_type()' id='159846220'>>

我错过了什么?请帮帮我。

【问题讨论】:

    标签: python unit-testing urllib2 python-mock


    【解决方案1】:

    你正在修补错误的东西:看看Where to patch

    api.py通过

    from urllib2 import urlopen
    from urllib2 import Request
    

    您在文件中创建对 urlopenRequest 的本地引用。通过mock.patch('urllib2.urlopen'),您正在修补原始参考,而让api.py 保持不变。

    所以,用

    替换你的补丁
    @mock.patch('api.Request')
    @mock.patch('api.urlopen')
    

    应该解决您的问题....但还不够。

    在您的测试用例中 api.Request 未使用,但 urllib2.urlopen() 通过使用修补版本创建 Request:这就是为什么 Request().get_type()MagicMock

    要获得完整的修复,您应该完全更改您的测试。先上代码:

    @mock.patch('api.urlopen', autospec=True)
    def test_call_api(self, urlopen):
        urlopen.return_value.read.return_value = 'mocked'
        _api = API()
        self.assertEqual(_api.call_api('https://google.com'), 'mocked')
        urlopen.assert_called_with('https://google.com')
    

    现在澄清一下...在您的测试中,您没有调用Request(),因为您只传递了第一个参数,所以我删除了无用的补丁。此外,您正在修补urlopen 函数而不是urlopen 对象,这意味着您要模拟的read() 方法是urlopen() 调用返回的对象的方法。

    最后,我在urlopen 呼叫和autospec=True 上添加检查,这始终是一个好习惯。

    【讨论】:

    • 我进行了更改。 _api.call_api('https://google.com') 的值是 &lt;MagicMock name='urlopen().read()' id='3069563372'&gt;,它与“mocked”不匹配。为什么?附言我在 test_api.py 中用assert 更新了最后一行
    • @Hussain 现在应该没问题了
    • 是的。非常感谢。对模拟补丁的深刻见解。我想我可以进行一些更改并使其也适用于requests
    猜你喜欢
    • 2012-04-11
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多