Поддельные данные для модульных тестов каналов django

Ранее я уже задавал вопрос по этой теме, но в итоге отказался от него, потому что, похоже, нет способа ...

Но сейчас мне очень нужно написать модульные тесты для потребителей моего канала django, потому что приложение увеличивается в размерах, а ручное тестирование уже неэффективно. Поэтому я решил задать еще один вопрос, и на этот раз я сделаю все возможное, чтобы объяснить ситуацию.

Основной проблемой является "Генерация поддельных данных". Я использую factory_boy и faker вместе, чтобы генерировать поддельные данные для моих тестов. Когда я генерирую поддельные данные, они доступны из самого TestCase, но недоступны внутри потребителя. Позвольте мне показать вам это на примере, рассмотрим код ниже:

test_consumers.py

from chat.models import PersonalChatRoom
from users.models import User
from django.test import TestCase
from channels.testing import WebsocketCommunicator
from asgiref.sync import sync_to_async
from users.tests.test_setup import TestUtilsMixin
from astra_backend.asgi import application
from chat.tests.model_factory import PersonalChatRoomFactory


class TestPersonalChatRoomConsumer(TestCase, TestUtilsMixin):
    def setUp(self) -> None:
        super().setUp()
        self.chat_room = PersonalChatRoomFactory()
        self.u1 = self.chat_room.user_1
        self.u2 = self.chat_room.user_2
     -> print("setup: (user): ", User.objects.all())
     -> print("setup: (personal chat room): ", PersonalChatRoom.objects.all())

    async def test_personal_chat_room_connection(self):
     -> await sync_to_async(print)("test (user): ", User.objects.all())
     -> await sync_to_async(print)("test (personal chat room): ", PersonalChatRoom.objects.all())

        com = WebsocketCommunicator(application, f'chat/personal/{self.chat_room.pk}/')
        connected, _ = await com.connect()
        self.assertTrue(connected)

consumers.py

...
class PersonalChatConsumer(
        ChatRoomManagementMixin,
        MessageManagementMixin,
        JsonWebsocketConsumer
    ):
    message_serializer_class = PersonalMessageSerializer
    chat_room_class = PersonalChatRoom

    def connect(self):
     -> print("consumer (user): ", User.objects.all())
     -> print("consumer (personal chat room): ", PersonalChatRoom.objects.all())
        return super().connect() # some magic here
    
    ...

output

Я распечатываю содержимое базы данных в 3 различных секциях кода:

  • внутри метода setUp в классе TestPersonalChatRoomConsumer
  • внутри метода test_personal_chat_room_connection в классе TestPersonalChatRoomConsumer
  • внутри connect метода потребителя

Я ожидал, что результаты будут идентичными, но вот реальный результат при выполнении теста:

setup: (user):  <QuerySet [<User: joshua03@cervantes.net>, <User: pgolden@cummings.com>]>
setup: (personal chat room):  <QuerySet [<PersonalChatRoom: PV joshua03@cervantes.net and pgolden@cummings.com>]>
test (user):  <QuerySet [<User: joshua03@cervantes.net>, <User: pgolden@cummings.com>]>
test (personal chat room):  <QuerySet [<PersonalChatRoom: PV joshua03@cervantes.net and pgolden@cummings.com>]>
...
consumer (user):  <QuerySet []> # There are no users in the database
consumer (personal chat room):  <QuerySet []> # There are no chat rooms in the database

Почему данные, сгенерированные внутри метода setUp, не доступны внутри потребителя?

Вот что лично я считаю причиной проблемы:

  • возможно, что-то не так с транзакциями базы данных
  • возможно, дело в соединениях базы данных
  • возможно, потребитель использует другую базу данных

Если вам нужна дополнительная информация, пожалуйста, оставьте комментарий ниже. Я предоставлю их как можно скорее. Спасибо всем.

Проблема: Вы столкнулись с проблемой отсутствия данных из-за асинхронных вызовов.

Решение: В django.test есть тестовый класс под названием TransactionTestCase. Используя его, мы можем преодолеть проблему отсутствия данных асинхронных.

Сделайте следующие изменения и все готово:

test.py

Замените TestCase на TransactionTestCase и все готово.

from django.test import TransactionTestCase
class TestTheTestConsumer(TransactionTestCase):

Выход:

python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
User (test.setUp):  <QuerySet [<User: someuser1>, <User: someuser2>]>
User (test.test_users_are_listed_correctly):  <QuerySet [<User: someuser1>, <User: someuser2>]>
User (consumer.connect):  <QuerySet [<User: someuser1>, <User: someuser2>]>
User (consumer.send_user_list):  <QuerySet [<User: someuser1>, <User: someuser2>]>
User (results):  [{'username': 'someuser1', 'id': 1}, {'username': 'someuser2', 'id': 2}]
Вернуться на верх