Python 3 Pytest: 如何模拟请求的urlopen响应和标头?

3

我已经将我的代码拆分为单独的函数以进行单元测试。我正在尝试使用Pytest测试框架,目前只了解基础知识。

实际上我并不想向互联网发送请求——这将是一个无用的测试,因为我只会测试urllib库。然而,我确实想测试响应的处理方式。

我有这个函数来发出请求。

def request_url(url):
    return request.urlopen(url)

然后我正在检查内容类型:

def get_document_type(req):
    """ checks if document is html or plain text """
    doc_type = req.info().get_content_type()
    if doc_type == "text/html":
        return "html"
    elif doc_type == "text/plain":
        return "txt"
    else: 
        return error_message["unsupported_document_type"]

接下来我需要进行测试,并需要模拟每个结果。如果这是Node.js,我可以使用类似于rewire或sinon stub的东西。

def get_content(req):
    doc_type_response = get_document_type(req)
    if doc_type_response == "html":
        # handle html content
    elif get_type_response == "txt":
        # handle plain text
    else:
        return doc_type_response

这个单元测试可以工作,但我不想进行真正的调用。

def test_request_url():
    url = request_url(url_to_try).info().get_content_type() 
    assert url == "text/plain"

有人知道最好的方法吗?这个问题与IT技术相关。

不确定我是否完全理解了您的问题,但是 mock Python 库不就是用于这些目的吗?在此处阅读更多 - kingmakerking
是吗?我真的不知道。也许你可以展示一个实例实现吗? - SarahJessica
我分享的链接有非常清晰的示例。 - kingmakerking
这个例子使用了unittest。我尝试实现的内容比仅仅模拟状态码要复杂一些。我已经尝试过并得到了"ModuleNotFoundError: No module named 'mock'"的错误,所以它只在unittest中可用吗(我也不知道)? - SarahJessica
1个回答

4

有一个名为requests-mock的包https://pypi.org/project/requests-mock/,可用于模拟API调用,但仅适用于requests库。以下是一个带有headers/text的示例:

import unittest
import requests_mock
import requests

class TestImplementations(unittest.TestCase):

    @requests_mock.mock()
    def test_get_project(self, mock_for_requests):
        API_URL = "https://someapi.com"

        #mocking your request(s)
        expected_headers = {'Content-Type': 'text/plain'}
        expected = 'some_text'
        mock_for_requests.get(API_URL + "/someendpoint", headers=expected_headers, text=expected)

        #running your code with requests
        response = requests.get(API_URL + "/someendpoint")

        #comparing output
        self.assertEqual(response.headers, expected_headers)
        self.assertEqual(response.text, expected)

嗨Dmytro,谢谢你的回复。我尝试使用Pytest来实现这个,但是出现了"fixture 'mock_for_requests' not found"的错误。我认为它需要在测试之外定义,然后传递进去。不幸的是,这里的文档https://requests-mock.readthedocs.io/en/latest/pytest.html并没有提供任何有用的信息。 - SarahJessica
嗨。你在用哪个Python版本?requests_mock至少需要3.6版本。我已经成功地在PyCharm和Python 3.8上运行了这段代码。 - Dmytro
我正在使用3.8版本。我认为问题在于我使用的是Pytest而不是Unittest进行测试。 - SarahJessica
这在使用pytest时也可以正常工作:python3.8 -m pytest script.py - Dmytro
1
这段代码的问题在于你混合使用了pytest和unittest。它们可以一起工作,但是pytest的fixture用法与unittest不同。对于requests-mock,没有最低的Python版本要求,而是需要将fixture作为一个正确的pytest fixture来调用。请参考https://dev59.com/Na3la4cB1Zd3GeqPVPuw#52065289了解更多背景信息。 - jamielennox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接