如何将数据模拟为请求。响应键入python

2024-03-28 13:58:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我想写一些测试用例来练习isinstance(obj)中的object_check,请求。响应)逻辑。在我创建模拟数据作为请求.post. 模拟数据的类型始终是模拟类。这样,我如何重写模拟数据以便模拟数据可以是请求。回应?所以我可以练习d = obj.json()?在

from unittest.mock import patch, Mock
import unittest
import requests
from requests.exceptions import HTTPError
import pytest
def object_check(obj):
    if isinstance(obj, bytes):
        d = ujson.decode(obj.decode())
    elif isinstance(obj, requests.Response):
        d = obj.json()
    else:
        raise ValueError('invalid type')
    return d

def service_post(params):
    """
    trivial function that does a GET request
    against google, checks the status of the
    result and returns the raw content
    """
    url = "https://www.iamdomain.com"
    params = {'number': 1234, 'user_id': 1, 'name': 'john'}
    resp = requests.post(url, data=params)
    return object_check(resp)

@patch.object(requests, 'post')
def test_service_post(mock_request_post):
    data = {'number': 0000, 'user_id': 0, 'name': 'john'}
    def res():
        r = Mock()
        r.status_code.return_value = 200
        r.json.return_value = data
        return r
    mock_request_post.return_value = res()
    assert data == service_post(data)

Tags: 数据importjsonobjdatareturnobjectdef
3条回答

你可以这样做:

@patch.object(requests, 'post')
def test_service_post(mock_request_post):
    data = {'number': 0000, 'user_id': 0, 'name': 'john'}
    def res():
        r = requests.Response()
        r.status_code = 200
        def json_func():
            return data
        r.json = json_func
        return r
    mock_request_post.return_value = res()
    assert data == service_post(data)

当我在本地运行这个测试时,它通过了。注意Mock是一种很小的气味。

我以前是Mock的超级粉丝。不过,随着我成长为一个开发人员,我真的努力避免它。它可以欺骗您进入一些非常糟糕的设计,并且它们很难维护(特别是因为您正在修改Mock来保存返回值)。^{prod1>你的服务可能会继续进行安全性测试(如果你的cd1的安全性测试通过的话)。我不认为你真的需要它。两种选择:

  1. 你可以点击任何你想要点击的服务,然后用pickle序列化(保存)这个响应,然后存储到磁盘(保存在你的测试套件中)。然后让您的单元测试读回它并使用实际的响应对象。您仍然需要patch而不是requests.post,但至少返回值将为您排队,并且您不必随着需求/应用程序的增长而添加或修改它们。在
  2. 只要上网。完全忘掉patch:只需在测试中发布文章并检查响应。当然,这可能很慢,而且只有在你有互联网的情况下才有效。你会得到愚蠢的纯粹主义者,他们会告诉你不要在单元测试中这样做。如果你遇到一个纯粹的人,也许可以把它转移到一个集成测试中。但是说真的,在prod中做你真正要做的事情是没有替代品的,这样做的好处是,如果web服务发生了变化,那么你马上就会知道它并可以修改你的代码。缺点是它会减慢您的测试套件,而且它是一个潜在的不可靠的测试(如果web服务停止运行,您的测试将失败…但事实上知道这一点可能是很好的)。在

我建议如果Web服务不稳定(即容易更改),请使用选项2。否则,使用选项1。或者组合使用(Mockpatch进行单元测试,并在集成测试中命中服务)。只有你能决定!在

祝你好运!在

如果要模拟textcontent@属性值,请在text周围使用PropertyMock

@patch.object(requests, 'post')
def test_service_post(mock_request_post):
    data = {'number': 0000, 'user_id': 0, 'name': 'john'}
    def res():
        r = requests.Response()
        r.status_code = 200
        type(r).text = mock.PropertyMock(return_value=my_text)  # property mock
        def json_func():
            return data
        r.json = json_func
        return r
    mock_request_post.return_value = res()
    assert data == service_post(data)

实例化mock时使用^{}参数:

>>> from unittest.mock import Mock
>>> from requests import Response
>>> m = Mock(spec=Response)
>>> m.__class__
requests.models.Response
>>> isinstance(m, Response)
True

另请注意,r.status_code.return_value = 200不能与speccing一起使用;请直接设置该值:

^{pr2}$

相关问题 更多 >