TypeError:Mock 类型的对象不是 JSON 可序列化的

我的代码中有以下测试文件:

# Copyright 2017-2021 The Wazo Authors  (see the AUTHORS file)
# SPDX-License-Identifier: GPL-3.0-or-later

import json
from hamcrest import assert_that, equal_to, has_entries
from mock import ANY, Mock, patch, sentinel as s
from wazo_auth.config import _DEFAULT_CONFIG
from wazo_auth.tests.test_http import HTTPAppTestCase

ADDRESS_NULL = {
    'line_1': None,
    'line_2': None,
    'city': None,
    'state': None,
    'country': None,
    'zip_code': None,
}
ADDRESS_EMPTY = {
    'line_1': '',
    'line_2': '',
    'city': '',
    'state': '',
    'country': '',
    'zip_code': '',
}

class TestTenantPost(HTTPAppTestCase):

    url = '/0.1/tenants'

    def setUp(self):
        config = dict(_DEFAULT_CONFIG)
        config['enabled_http_plugins']['tenants'] = True
        super().setUp(config)

    @patch('wazo_auth.plugins.http.tenants.http.TenantDetector')
    def test_invalid_posts(self, TenantDetector):
        TenantDetector.autodetect.return_value = Mock(uuid=s.tenant_uuid)

        invalid_datas = [
            ('name', {'name': 42, 'slug': 'abc'}),
            ('name', {'name': 100 * 'foobar', 'slug': 'abc'}),
            ('slug', {'slug': 'a-b'}),
            ('slug', {'slug': 'a b'}),
            ('slug', {'slug': False}),
            ('slug', {'slug': 0}),
        ]

        for field, invalid_data in invalid_datas:
            result = self.post(invalid_data)
            assert_that(result.status_code, equal_to(400), invalid_data)
            assert_that(
                result.json,
                has_entries(
                    error_id='invalid-data',
                    message=ANY,
                    resource='tenants',
                    details=has_entries(
                        field,
                        has_entries(constraint_id=ANY, constraint=ANY, message=ANY),
                    ),
                ),
                invalid_data,
            )

    @patch('wazo_auth.plugins.http.tenants.http.TenantDetector')
    def test_empty_tenant_addresses(self, TenantDetector):
        TenantDetector.autodetect.return_value = Mock(uuid=s.tenant_uuid)

        invalid_bodies = [
            ('address', {'address': dict(
                line_1='',
                line_2='',
                city='',
                state='',
                zip_code='',
                country='',
            )}),
            ('address', {'address': dict(
                line_1=None,
                line_2=None,
                city=None,
                state=None,
                zip_code=None,
                country=None,
            )}),
        ]

        for field, invalid_body in invalid_bodies:
            result = self.post(invalid_body)
            assert_that(result.status_code, equal_to(400), invalid_body)
            assert_that(
                result.json,
                has_entries(
                    error_id='invalid-data',
                    message='Invalid tenant address length',
                    resource='tenants',
                    details=has_entries(
                        field,
                        has_entries(
                            constraint_id='length', constraint=ANY, message=ANY
                        ),
                    ),
                ),
                invalid_body,
            )

    @patch('wazo_auth.plugins.http.tenants.http.TenantDetector')
    def test_that_validated_args_are_passed_to_the_service(self, TenantDetector):
        TenantDetector.autodetect.return_value = Mock(uuid=s.tenant_uuid)

        body = {'name': 'foobar', 'slug': 'slug', 'ignored': True}
        self.tenant_service.new.return_value = {
            'name': 'foobar',
            'uuid': '022035fe-f5e5-4c16-bd5f-8fea8f4c9d08',
        }

        result = self.post(body)

        assert_that(result.status_code, equal_to(200))
        assert_that(result.json, equal_to(self.tenant_service.new.return_value))
        self.tenant_service.new.assert_called_once_with(
            uuid=None,
            name='foobar',
            slug='slug',
            phone=None,
            contact_uuid=None,
            parent_uuid=s.tenant_uuid,
            address=dict(
                line_1=None,
                line_2=None,
                city=None,
                state=None,
                zip_code=None,
                country=None,
            ),
        )

    def post(self, data):
        return self.app.post(self.url, data=json.dumps(data), headers=self.headers)

当我在 test_empty_tenant_addresses 上面定义测试函数时,出现以下故障:


=================================== FAILURES ===================================
__________________ TestTenantPost.test_empty_tenant_addresses __________________

self = <wazo_auth.plugins.http.tenants.tests.test_tenants.TestTenantPost testMethod=test_empty_tenant_addresses>
TenantDetector = <MagicMock name='TenantDetector' id='140628422384888'>

    @patch('wazo_auth.plugins.http.tenants.http.TenantDetector')
    def test_empty_tenant_addresses(self, TenantDetector):
        TenantDetector.autodetect.return_value = Mock(uuid=s.tenant_uuid)

        invalid_bodies = [
            ('address', {'address': dict(
                line_1='',
                line_2='',
                city='',
                state='',
                zip_code='',
                country='',
            )}),
            ('address', {'address': dict(
                line_1=None,
                line_2=None,
                city=None,
                state=None,
                zip_code=None,
                country=None,
            )}),
        ]

        for field, invalid_body in invalid_bodies:
            result = self.post(invalid_body)
>           assert_that(result.status_code, equal_to(400), invalid_body)
E           AssertionError: {'address': {'line_1': '', 'line_2': '', 'city': '', 'state': '', 'zip_code': '', 'country': ''}}
E           Expected: <400>
E                but: was <500>

wazo_auth/plugins/http/tenants/tests/test_tenants.py:92: AssertionError
------------------------------ Captured log call -------------------------------
ERROR    flask.app:app.py:1761 Exception on /0.1/tenants [POST]
Traceback (most recent call last):
  File "/root/wazo-auth/.tox/py37/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/root/wazo-auth/.tox/py37/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/root/wazo-auth/.tox/py37/lib/python3.7/site-packages/flask_restful/__init__.py", line 462, in wrapper
    return self.make_response(data, code, headers=headers)
  File "/root/wazo-auth/.tox/py37/lib/python3.7/site-packages/flask_restful/__init__.py", line 491, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "/root/wazo-auth/.tox/py37/lib/python3.7/site-packages/flask_restful/representations/json.py", line 21, in output_json
    dumped = dumps(data, **settings) + "n"
  File "/usr/lib/python3.7/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Mock is not JSON serializable

显然,失败是由我添加的函数中的这一行引起的:

>           assert_that(result.status_code, equal_to(400), invalid_body)

给出以下错误消息:

  File "/usr/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Mock is not JSON serializable

我尝试了一些通过搜索/查找问题找到的解决方案,但我无法解决问题。请帮我修一下,谢谢。

P.S:原始代码在以下github存储库中:

https://github.com/wazo-platform/wazo-auth

stack overflow TypeError: Object of type Mock is not JSON serializable
原文答案
author avatar

接受的答案

对于与我面临同一问题的任何人,我通过更改以下字典声明找到了解决方案:

invalid_bodies = [
            ('address', {'address':
                'line_1':'',
                'line_2':'',
                'city':'',
                'state':'',
                'zip_code':'',
                'country':'',
           }),

        ]

我通过记录输入和预期断言输出来找到解决方案;我注意到断言失败了,因为它期望 OrderedDict 对象而不是 dictionary

显然,不接受使用Python KeyWorkd dict 来声明您的字典(不接受JSON serializable;它将其转换为 OrderedDict type)。另外,我删除了我拥有的第二个正文( None 地址字段)。


答案: