Python Django - Передача нескольких параметров в Factory во время тестирования

В настоящее время я работаю над приложением для социальных сетей. В этом приложении текущие пользователи могут приглашать своих друзей по электронной почте присоединиться к приложению (в частности, присоединиться к "каналу" приложения, как Discord). В этом проекте я работаю над функциональностью, при которой пользователь получит ошибку, если попытается пригласить кого-то, кто уже есть в приложении (имеются в виду люди, которые уже есть в базе данных приложения). Я работаю над модульными тестами, которые обеспечивают появление сообщений об ошибках, когда пользователи определяются как уже существующие.

Мне удалось заставить работать первый сценарий, но я немного запутался во втором.

Вот файл, который является центральным для обоих тестов.

factories.py

class ChannelFactory(factory.django.DjangoModelFactory)
 class Meta:
  model = Channel
  id = int
  name = str

class CurrentUserFactory(factory.django.DjangoModelFactory)
 class Meta:
  model = CurrentUser
  user_email = user_email
  channel = models.ForeignKey(Channel)

Сценарий №1 (в настоящее время работает) - один новый пользователь приглашается присоединиться к приложению, но уже существует в базе данных приложения

test_forms.py

from tests.factories import ChannelFactory, CurrentUserFactory

@pytest.mark.django_db
def test_that_current_user_cannot_be_reinvited(email, error_message):
"""user that is already in the specific channel cannot be reinvited"""

email = "user@test.com"
error_message = "user@test.com already exists in this channel"

# I am not specifying the channel name because the factory object is supposed to generate it automatically
current_user = CurrentUserFactory(user_email='user@test.com')

invite_form = forms.UserRequestForm({"email":email, channel=current_user.channel)

assert not invite_form is valid()
assert invite_form.errors["email"][0] = error_message

Результат: Тест пройден!

Однако тест проходит в основном потому, что тестируется только один пользователь.

Итак, моя задача - создать тест, чтобы посмотреть, что произойдет, если пригласить сразу несколько человек. Приложение позволяет вводить строку, разделенную запятыми, поэтому теоретически можно пригласить до десяти писем одновременно.

Сценарий №2 - два новых пользователя приглашены на один и тот же канал и оба существуют в базе данных приложения. Здесь я сталкиваюсь с проблемами, потому что мне нужно как-то убедиться, что CurrentUsers генерируются в один и тот же канал.

from tests.factories import CurrentUserFactory
    
@pytest.mark.django_db
def tests_that_multiple_current_users_cannot_be_reinvited(emails, error_message):
"""users that are already in the specific channel cannot be reinvited"""

emails = ["user@test.com", "user2@test.com"]
error_message = "The following users already exist in this channel: user@test.com, user2@test.com"

#here, I attempt to "force" a Channel instance
channel = Channel(id="5", name="Hometown Friends")

current_users = [
(CurrentUserFactory(user_email='user@test.com', channel=channel)),
(CurrentUserFactory(user_email='user2@test.com', channel=channel)),
]

invite_form = forms.UserRequestForm({"email":emails, "channel":current_users.channel})

assert not invite_form is valid()
assert invite_form.errors["email"][0] = error_message

Когда я пытаюсь запустить тест:

E AttributeError: 'tuple' object has no attribute 'channel'

Мне интересно, могу ли я легко решить эту проблему, пытаясь работать с кортежем, или есть гораздо более простой метод, который я почему-то не вижу. Буду очень признателен за помощь!

Кортеж - это другой способ хранения нескольких объектов вместе, такой же, как список или массив.

Вы пытаетесь получить атрибут 'channel' из кортежа здесь:

invite_form = forms.UserRequestForm({"email":emails, "channel":current_users.channel})

Поскольку вы поместили два объекта в кортеж, вам нужно указать python точный адрес объекта, у которого вы хотите получить атрибут.

Попробуйте вместо этого:

invite_form_1 = forms.UserRequestForm({"email":emails[0], "channel":current_users[0].channel})
invite_form_2 = forms.UserRequestForm({"email":emails[1], "channel":current_users[1].channel})

Теперь вы говорите python посмотреть на первый объект в кортеже current_users и получить его атрибут 'channel', а затем во второй строке вы смотрите на второй объект в этом кортеже.

Очевидно, что в этом случае вы также должны утверждать обе формы отдельно.

Если вы хотите провести тест для х количества форм, вы также можете использовать цикл:

invite_forms = []

for i in x:
    invite_forms.append(
    forms.UserRequestForm({"email":emails[i], "channel":current_users[i].channel}))

(Только убедитесь, что у emails и current_users достаточно объектов!)

Здесь вы добавляете x объектов UserRequestForm в кортеж/список invite_forms.

Опять же, это потребует от вас итерации по утверждениям.

Вернуться на верх