Поддельные данные для модульных тестов каналов 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}]