TypeError: Object of type Mock is not JSON serializable
I have the following test file in my code:
# 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)
When i defined the test function above test_empty_tenant_addresses
, I get the following failure:
=================================== 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
Apparently, the failure is caused by this line in my added function:
> assert_that(result.status_code, equal_to(400), invalid_body)
which gives the following error message:
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
I have tried some solutions that I found by searching/looking for the issue, but I could not fix the issue. Please help me fix it, thanks.
P.S: The original code is in the following github repository:
https://github.com/wazo-platform/wazo-auth
Solution 1:
For anyone facing the same issue as me, I found the solution by changing my dictionary declaration as below:
invalid_bodies = [
('address', {'address':
'line_1':'',
'line_2':'',
'city':'',
'state':'',
'zip_code':'',
'country':'',
}),
]
I found the solution by logging both the input and the expected assertion output; and I noticed that the assertion failed because it was expecting an OrderedDict
object instead of a dictionary
.
Apparently, declaring your dictionary using the python keyworkd dict
is not accepted (not JSON serializable; it converts it to OrderedDict
type). Also, I removed the second body that I had (dictionary with None
address fields).