Skip to content

Commit 84da5a7

Browse files
committed
Improve test coverage for exception handler
1 parent 0473268 commit 84da5a7

File tree

5 files changed

+35
-10
lines changed

5 files changed

+35
-10
lines changed

drf_simple_api_errors/exception_handler.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ def exception_handler(exc: Exception, context: ExceptionHandlerContext) -> Respo
4444
# This is because it's not good practice to expose the details of
4545
# unhandled exceptions to the client.
4646
if not isinstance(exc, exceptions.APIException):
47+
# Raise a ServerError exception instead of returning None, because
48+
# we can control the response format this way.
4749
logger.info("Server error (500) from unexpected exception.", exc_info=True)
4850
return ServerError
4951

drf_simple_api_errors/formatter.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,10 @@ def format_exc(exc: exceptions.APIException) -> APIErrorResponseDict:
101101
# Create the API error response based on the exception detail...
102102
if isinstance(exc_detail, dict):
103103
return _format_exc_detail_dict(data, exc_detail)
104-
elif isinstance(exc_detail, list):
105-
# If the exception detail is a list, we will return all the errors
106-
# in a single list.
107-
return _format_exc_detail_list(data, exc_detail)
108104
else:
109-
return data.to_dict()
105+
# If the exception detail in not a dict, it must be a list, and
106+
# we will return all the errors in a single list.
107+
return _format_exc_detail_list(data, exc_detail)
110108

111109

112110
def _format_exc_detail_dict(

tests/test_exception_handler.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import pytest
66

7+
from drf_simple_api_errors import exceptions
78
from drf_simple_api_errors.exception_handler import exception_handler
89
from tests.utils import render_response
910

@@ -399,3 +400,12 @@ def test_drf_throttled(self, mocker, wait, expected_detail):
399400
"invalid_params": None,
400401
}
401402
assert render_response(response.data) == expected_response
403+
404+
def test_unexpected_exception(self, mocker):
405+
"""
406+
Test the exception handler for unexpected exceptions.
407+
This should return a 500 Internal Server Error response.
408+
"""
409+
exc = Exception("Unexpected error")
410+
response = exception_handler(exc, mocker.Mock())
411+
assert response is exceptions.ServerError

tests/test_formatter.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,32 @@ def test_exc_detail_is_dict_with_non_field_errors_formats(self, mocker, exc_deta
207207
assert data["invalid_params"] is None
208208

209209
@pytest.mark.parametrize(
210-
"exc_detail",
210+
"exc_detail, expected_detail",
211211
[
212-
"This is a non-field error.",
213-
["This is a non-field error."],
212+
("This is a non-field error.", ["This is a non-field error."]),
213+
(["This is a non-field error."], ["This is a non-field error."]),
214+
(
215+
["This is a non-field error.", "Another error."],
216+
["This is a non-field error.", "Another error."],
217+
),
218+
(
219+
[
220+
"This is a non-field error.",
221+
["Another error.", "Yet another error."],
222+
],
223+
["This is a non-field error.", "Another error.", "Yet another error."],
224+
),
214225
],
215226
)
216-
def test_exc_detail_is_list_formats(self, exc_detail):
227+
def test_exc_detail_is_list_formats(self, exc_detail, expected_detail):
217228
"""
218229
Test that when the exception detail is a list or a string,
219230
the detail is set to the error messages list and invalid_params is `None`.
220231
"""
221232
exc = drf_exceptions.ValidationError(exc_detail)
222233

223234
data = formatter.format_exc(exc)
224-
assert data["detail"] == ["This is a non-field error."]
235+
assert data["detail"] == expected_detail
225236
assert data["invalid_params"] is None
226237

227238
def test_format_exc_detail_is_list_error_when_unexpected_type(self):

tests/test_utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class TestCamelize:
1414
("first_name", "firstName"),
1515
("family_tree_name", "familyTreeName"),
1616
("very_long_last_name_and_first_name", "veryLongLastNameAndFirstName"),
17+
# This is a special case where the underscore is at the start
18+
# and should be removed, and the next character should be capitalized.
19+
("_special", "Special"),
1720
],
1821
)
1922
def test_with_camelize_settings_true(self, mocker, field_input, expected_output):
@@ -33,6 +36,7 @@ def test_with_camelize_settings_true(self, mocker, field_input, expected_output)
3336
"very_long_last_name_and_first_name",
3437
"very_long_last_name_and_first_name",
3538
),
39+
("_special", "_special"),
3640
],
3741
)
3842
def test_with_camelize_settings_false(self, field_input, expected_output):

0 commit comments

Comments
 (0)