В настоящее время я пишу тестовые примеры с использованием Django и хотел бы улучшить способ обработки ошибок, особенно отличая ошибки, возникающие в самих тестовых примерах, от ошибок, вызванных пользовательским кодом.
< h3>Контекст:
Предположим, пользователь пишет функцию для получения и увеличения количества лайков публикации:
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")
Вот тестовый пример для этой функции:
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)
Сценарий:
Теперь, если пользователь случайно изменил код, чтобы увеличить количество лайков на 2 вместо 1, и не сохранил объект публикации .
# 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")
Это приводит к следующему сбою теста:
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 = , 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 ===============================
Запрос на помощь:
Вместо отображения приведенной выше трассировки, которая явно указывает на ошибку тестового примера, я бы предпочел вернуть более пользовательский запрос. дружелюбное сообщение об ошибке, например:
Error 1: "Likes cannot be incremented by 2"
Error 2: "You used filter method instead of the get method in your function"
Есть ли способ отловить такие ошибки в тестовом примере и вернуть более удобочитаемое сообщение об ошибке? Буду очень признателен за любые рекомендации о том, как это реализовать.
Спасибо!
Изменить 1
Примечание. Я использую работника celery для запуска файла docker, который, в свою очередь, будет запускать тесты. Вот соответствующая часть файла Tasks.py, ответственная за ошибку печати:
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())
Подробнее здесь: https://stackoverflow.com/questions/790 ... test-cases
Обработка ошибок в тестовых примерах Django ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение