首页 > 解决方案 > 在 pytest 中使用自定义测试资源修补第三方客户端

问题描述

我为我在 Django 应用程序上下文中使用的第三方服务编写了一个客户端。我想在测试期间替换该客户端,这样我不仅可以修补客户端上的特定方法,而且还可以在测试资源中维护一些类似的状态,以模仿真正的第三方服务在生产中的情况。

我目前的设置是这样的:

# app/third_party_client.py

import requests


class TPC:
    def request_new(self, unique_id):
        resp = requests.get('http://foo.bar', data={'blah': unique_id})
        return {'vendor_id': resp.json()['vendor_id'], 'status': resp.json()['status']}

    def request_status_update(self, unique_id, vendor_id):
        resp = requests.get('http://foo.bar', data={'blah': unique_id, 'meh': vendor_id})
        return {'status: resp.json()['status']}
# app/models.py

from app.third_party_client import TPC

TPC_CLIENT = TPC()


class SomeModel:
    def do_something_with_third_party_service(self):
        response = TPC_CLIENT.request_new(self.unique_id)
        self.vendor_id = response.get('vendor_id')
        self.status = response.get('status')
        self.save()

    def check_status_of_something_with_third_party_service(self):
        response = TPC_CLIENT.request_status_update(self.unique_id, self.vendor_id)
        self.status = response.get('status')
        self.save()
# tests/resources.py
import random
import string


class TPCResource:
    def __init__(self):
        self.orders = {}

    def request_new(self, unique_id):
        vendor_id = ''.join(random.sample(string.ascii_uppercase + string.digits, 8))
        self.orders[unique_id] = vendor_id
        return {'vendor_id': vendor_id, 'status': 'pending'}

    def request_status_update(self, unique_id, vendor_id):
        if unique_id not in self.orders.keys() or self.orders[unique_id] == vendor_id:
            raise Exception('This mimics third party')

        return {'status': 'Completed'}   

我想弄清楚如何在代码路径调用等的测试期间用我的测试资源替换TPC(或其实例化形式) 。我在 pytest 中设置了固定装置等,但我很难弄清楚了解如何用自定义测试资源替换类或类的实例。大多数用于模拟、修补和猴子修补的文档都集中在方法/函数上。app/models.pyTPCResourcesome_model. do_something_with_third_party_service()

标签: pythonmockingpytest

解决方案


想象一下,对于未来的观众来说,这是一个“duh”的时刻,但您可以将替换资源传入mock.patch().

在上面示例的上下文中,我这样做了:

@pytest.fixture(autouse=True)
def patched_tpc_client(request):
    tpc_test_resource = TPCResource()
    with mock.patch('app.models.TPC_CLIENT', tpc_test_resource) as tpc_client:
        yield tpc_client


推荐阅读