I am currently writing test cases using Django and would like to improve the way we handle errors, particularly distinguishing between errors that arise from the test cases themselves and those caused by the user's code. Context: Let’s say a user writes a function to fetch and increment the likes count of a post: def fetch_post(request, post_id): try: post = Post.objects.get(id=post_id) except Post.DoesNotExist: raise Http404("Post not found") post.likes += 1 post.save() return HttpResponse("Post liked") Here’s the test case for that function: from django.test import TestCase from project_app.models import Post from django.urls import reverse from django.http import Http404 class FetchPostViewTests(TestCase): def setUp(self): self.post = Post.objects.create(title="Sample Post") def assertLikesIncrementedByOne(self, initial_likes, updated_post): if updated_post.likes != initial_likes + 1: raise AssertionError(f'Error: "Likes cannot be incremented by {updated_post.likes - initial_likes}"') def test_fetch_post_increments_likes(self): initial_likes = self.post.likes response = self.client.get(reverse('fetch_post', args=[self.post.id])) updated_post = Post.objects.get(id=self.post.id) self.assertLikesIncrementedByOne(initial_likes, updated_post) self.assertEqual(response.content.decode(), "Post liked") def test_fetch_post_not_found(self): response = self.client.get(reverse('fetch_post', args=[9999])) self.assertEqual(response.status_code, 404) Scenario: Now, if a user accidentally modifies the code to increment the likes by 2 instead of 1 and didn't save the post object. # Wrong code that will fail the test case def fetch_post(request, post_id): try: # used filter() method instead of get() method post = Post.objects.filter(id=post_id) except Post.DoesNotExist: raise Http404("Post not found") post.likes += 2 # incremented by two instead of 1 post.save() return HttpResponse("Post liked") This leads to the following test failure: test_cases/test_case.py:53: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/local/lib/python3.9/site-packages/django/test/client.py:742: in get response = super().get(path, data=data, secure=secure, **extra) /usr/local/lib/python3.9/site-packages/django/test/client.py:396: in get return self.generic('GET', path, secure=secure, **{ /usr/local/lib/python3.9/site-packages/django/test/client.py:473: in generic return self.request(**r) /usr/local/lib/python3.9/site-packages/django/test/client.py:719: in request self.check_exception(response) /usr/local/lib/python3.9/site-packages/django/test/client.py:580: in check_exception raise exc_value /usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py:47: in inner response = get_response(request) /usr/local/lib/python3.9/site-packages/django/core/handlers/base.py:181: in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ request = <WSGIRequest: GET '/fetch_post/9999/'>, post_id = 9999 def fetch_post(request, post_id): try: post = Post.objects.filter(id=post_id) except Post.DoesNotExist: raise Http404("Post not found") # Raise 404 if post does not exist > post.likes += 2 E AttributeError: 'QuerySet' object has no attribute 'likes' project_app/views.py:11: AttributeError ------------------------------ Captured log call ------------------------------- ERROR django.request:log.py:224 Internal Server Error: /fetch_post/9999/ Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner response = get_response(request) File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/app/project_app/views.py", line 11, in fetch_post post.likes += 2 AttributeError: 'QuerySet' object has no attribute 'likes' =========================== short test summary info ============================ FAILED test_cases/test_case.py::FetchPostViewTests::test_fetch_post_increments_likes FAILED test_cases/test_case.py::FetchPostViewTests::test_fetch_post_not_found ============================== 2 failed in 0.74s =============================== Request for Assistance: Instead of displaying the above traceback, which clearly indicates a test case error, I would prefer to return a more user-friendly error message like: Error 1: "Likes cannot be incremented by 2" Error 2: "You used filter method instead of the get method in your function" Is there a way to catch such errors within the test case and return a more human-readable error message? Any guidance on how to implement this would be greatly appreciated. Thank you! Edit 1 Note: I am using a celery worker to run the dockerfile that will in turn run the tests. Here is the relevant part of the tasks.py responsible for printing error: print("Running tests in Docker container...") test_result = subprocess.run( ["docker", "run", "--rm", "-v", f"{volume_name}:/app", "test-runner"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if test_result.returncode != 0: # Check for AssertionError messages in stdout error_message = test_result.stdout if "AssertionError" in error_message: # Extract just the assertion error message lines = error_message.splitlines() for line in lines: if "Error:" in line: submission.error_log = line.strip() # Save specific error message to the database raise Exception(line.strip()) Continue reading...