繁体   English   中英

Python - 具有副作用的模拟请求

[英]Python - Mock requests with side_effect

我正在尝试模拟我的请求。 有副作用。 我想为每个副作用值关联一个不同的 status_code,但到目前为止我没有成功。

    def test_func1(mocker):
        side_effect = ["Ok",'','','Failed']
    
        # This line should be changed
        fake_resp.status_code = 200
    
        fake_resp = mocker.Mock()
        fake_resp.json = mocker.Mock(side_effect=side_effect)
        
    
        mocker.patch("app.main.requests.get", return_value=fake_resp)
        
        # The func1 is executing multiple API calls using requests.get() and status_code is needed
        a = func1(a, b) 
    
        assert a == "something"

我一直无法找到一种方法(在文档和 SO 中)为每个模拟请求关联 status_code。

我在想这样的事情,但显然行不通:

    def test_func1(mocker):
        side_effect = [(status_code=200, return="Ok"),
                   (status_code=204, return=""), 
                   (status_code=204, return=""),
                   (status_code=500, return="Failed")]
        ....

编辑:添加 func1 代码

from datetime import datetime, timedelta
import requests

def func1(days, delta_1):
    """
    days: number of days before first search (80, 25, 3)
    delta_1: number of days for the date range search (40, 20, 15)
    """
    now = datetime.now()
    start_date = now + timedelta(days=days)
    
    # Var to stop loop when price is found
    loop_stop = 0
    
    # Var to stop loop when search date is more than a year later
    delta_time = 0

    price = 0
    departureDate = "n/a"

    # For loop to check prices till one year. 
    while loop_stop == 0 and delta_time < (365 - days):
        date_range = (
            (start_date + timedelta(days=delta_time)).strftime("%Y%m%d")
            + "-"
            + (start_date + timedelta(days=delta_time + (delta_1 / 2))).strftime(
                "%Y%m%d"
            )
        )
        
        # Needs to be mocked
        response = requests.get("fake_url_using_date_range_var")
        
        if response.status_code == 204:
            print("No data found on this data range")
            delta_time += delta_1
        elif response.status_code == 200:
            price = response.json()["XXX"][0]
            departureDate = response.json()["YYY"][0]
            loop_stop = 1
        else:
            raise NameError(
                response.status_code,
                "Error occured while querying API",
                response.json(),
            )
        
    return price, departureDate

模块unittest (不是pytest )的可能解决方案

我在@baguette 添加真正的函数func1()之前写了这个答案,所以我创建了一个名为my_file_01.py的文件,其中包含我的生产函数func1()

import requests

def func1():
    response1 = 'empty1'
    response2 = 'empty2'
    r = requests.get('http://www.someurl.com')
    if r.status_code == 200:
        response1 = r.json()
    r = requests.get('http://www.some_other_url.com')
    if r.status_code == 500:
        response2 = r.error_message
    return [response1, response2]

如您所见, func1()调用requests.get()两次并检查响应的状态代码。

我已将测试代码插入到具有以下内容的不同文件中:

import unittest
from unittest import mock
from my_file_01 import func1

def request_resp1(url):
    response_mock = mock.Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {'key1': 'value1'}
    return response_mock


def request_resp2(url):
    response_mock = mock.Mock()
    response_mock.status_code = 500
    response_mock.error_message = "Failed"
    return response_mock

class TestFunc1(unittest.TestCase):
    @mock.patch("my_file_01.requests")
    def test_func1(self, mock_requests):
        print("test func1()")
        mock_requests.get.side_effect = [request_resp1(""), request_resp2("")]
        [response1, response2] = func1()
        print("response1 = " + str(response1))
        print("response2 = " + str(response2))

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

测试文件定义了包含测试方法TestFunc1 test_func1()的测试类 TestFunc1。

此外,在文件中定义了 2 个函数,称为request_resp1()request_resp2() 这些函数用于定义不同的响应值,以便第一次调用requests.get()成功 ( status_code = 200 ),而第二次调用requests.get()失败 ( status_code = 500 )。

如果您尝试执行测试代码,您会看到func1()为响应的 2 个不同的 status_codes 返回不同的值。

基于@frankfalse 的解决方案,这两个模拟函数可以用一个类代替。

class MockResponse:
    def __init__(self, json_data, status_code=requests.codes.ok):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM