首页 > 解决方案 > 如何以 Python 方式测试是否在 Python 中使用某个参数调用函数?

问题描述

我有一个包含端点的 Django 代码库。端点做了很多事情,我现在想检查端点是否do_metadata_request使用特定令牌调用函数(粘贴在下面)。

def do_metadata_request(url_info, token):
    metadata_url = f"{settings.META_SERVER_BASE_URL}/{url_info['dossier']}"

    headers = {}
    if token:
        headers['Authorization'] = token

    return requests.get(metadata_url, headers=headers)

所以经过一番摆弄,我做了下面的设置。它可以工作,但它在我在测试本身之外定义的模拟函数中进行实际测试。它根本感觉不到优雅或 Pythonic。我宁愿在测试中做断言,或者至少在测试中定义 mock_do_metadata_request。

有人知道如何更优雅地做到这一点吗?

class MockResponse:
    def __init__(self, status_code, json_content=None, content=None, headers=None):
        self.status_code = status_code
        self.json_content = json_content
        self.content = content
        self.headers = headers

    def json(self):
        return self.json_content

MOCK_TOKEN = "Bearer " + create_test_token([settings.EXTENDED_SCOPE])

def mock_do_metadata_request(url_info, token):
    assert token == MOCK_TOKEN
    return MockResponse(
        200,
        json_content={
            'access': settings.ACCESS_RESTRICTED,
            'documents': [{'barcode': '123', 'access': settings.ACCESS_RESTRICTED}]
        }
    )


class TestFileRetrieval(TestCase):
    def setUp(self):
        self.c = Client()

    @patch('project.metadata.do_metadata_request', side_effect=mock_do_metadata_request)
    def test_token_is_passed_on_to_metadata_server(self, mock_do_metadata_request):
        header = {'HTTP_AUTHORIZATION': MOCK_TOKEN}
        response = self.c.get(IMG_URL, **header)

标签: pythondjangounit-testingmockingpytest

解决方案


您可以使用对象的各种assert_called,asset_called_with等方法Mock来断言调用模拟时使用的参数,或者您可以使用call_argscall_args_list获取调用模拟时使用的参数。如果您不在乎特定参数在调用中具有什么值,则可以使用unittest.mock.ANY代替它。Mock您可以从文档中引用类的这些和其他方法/属性。可以为您工作的实现可以编写如下:

from unittest.mock import ANY


class TestFileRetrieval(TestCase):
    def setUp(self):
        self.c = Client()

    @patch('project.metadata.do_metadata_request')
    def test_token_is_passed_on_to_metadata_server(self, mock_do_metadata_request):
        mock_do_metadata_request.return_value = MockResponse(
            200,
            json_content={
                'access': settings.ACCESS_RESTRICTED,
                'documents': [{'barcode': '123', 'access': settings.ACCESS_RESTRICTED}]
            }
        )
        header = {'HTTP_AUTHORIZATION': MOCK_TOKEN}
        response = self.c.get(IMG_URL, **header)
        mock_do_metadata_request.assert_called_with(ANY, MOCK_TOKEN)

推荐阅读