2

I'm writing tests for a Django Channels application following the documentation. I can successfully test connection and communication with the WebSocket consumer. However, in one of the tests I need to create a user.

This is my test method:

@pytest.mark.django_db
@pytest.mark.asyncio
async def test_1():
    my_user = get_user_model().objects.create_user(username='my_user', email='user@user.com', password='123456')
    my_user.save()

    print(User.objects.all())

    communicator = WebsocketCommunicator(MyConsumer, '/websocket/')
    communicator.instance.scope['user'] = my_user
    connected, subprotocol = await communicator.connect()
    assert connected
    await communicator.send_json_to({
        'command': 'test',
    })
    response = await communicator.receive_json_from(timeout=5)
    await communicator.disconnect()

The error occurs inside the method that handles the 'command' == 'test' case. When it tries to save another model instance that has User as a foreign key, the test fails.

client = Client(user=scope['user'])
client.save()

If I add a print(User.objects.all()) to the method inside the consumer (between the previous two lines), it returns an empty QuerySet, while the first print in the test method itself returns the created user. Of course, since there is no User, the test fails with:

django.db.utils.IntegrityError: insert or update on table "chat_client" violates foreign key constraint "chat_client_user_id_d10928fc_fk_auth_user_id"
DETAIL:  Key (user_id)=(1) is not present in table "auth_user".

I tried turning user creation into another async method and awaiting for it, but nothing changed. Why is the User table getting emptied during the test's execution? How can I keep data created at the beginning of the test?

sanyassh
  • 8,100
  • 13
  • 36
  • 70
Vin
  • 309
  • 1
  • 11
  • 1
    You need to make the test transactional; check out a working example [here](https://stackoverflow.com/questions/49136564/django-channels-2-accessing-db-in-tests). – hoefling May 16 '19 at 20:44

1 Answers1

4

As indicated by @hoefling in the comments, the only thing missing was to make the test transactional, as seen in this question.

In my case, I only had to change the test decorator to:

@pytest.mark.django_db(transaction=True)
Vin
  • 309
  • 1
  • 11