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.
Опять же, это потребует от вас итерации по утверждениям.