Как создать пользователя-администратора с помощью Factory_Boy?

Я относительный начинающий Django и просто начал выполнять некоторые тесты для своих проектов. Я хочу создать функциональный тест с селеном, который входит в сайт администратора Django.

Сначала я познакомился с этим учебным пособием http://www.tdd-django-tutorial.com/tutorial/1/ и использовал инструменты и дампдаты, чтобы сделать информацию учетной записи администратора доступной для тестового приложения (которое создает новую базу данных). Это прекрасно работает.

Затем я хотел посмотреть, смогу ли я сделать то же самое с заводским мальчиком, чтобы заменить светильники. Фабричный мальчик работает, создавая необходимый объект в файле tests.py, который кажется мне более чистым. Почему-то я не могу заставить это работать, и документация Factory_boy не слишком полезна...

Вот мой test.py

from django.test import LiveServerTestCase
from django.contrib.auth.models import User
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import factory

class UserFactory(factory.Factory):
    FACTORY_FOR = User

    username = 'jeff'
    password = 'pass'
    is_superuser = True

class AdminTest(LiveServerTestCase):

    def setUp(self):
        self.browser = webdriver.Firefox()

    def tearDown(self):
        self.browser.quit()

    def test_if_admin_login_is_possible(self):
        jeff = UserFactory.create()

        # Jeff opens the browser and goes to the admin page
        self.browser = webdriver.Firefox()
        self.browser.get(self.live_server_url + '/admin/')

        # Jeff sees the familiar 'Django Administration' heading
        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Django administration', body.text)

        # Jeff types in his username and password and hits return
        username_field = self.browser.find_element_by_name('username')
        username_field.send_keys(jeff.username)
        password_field = self.browser.find_element_by_name('password')
        password_field.send_keys(jeff.password)
        password_field.send_keys(Keys.RETURN)

        # Jeff finds himself on the 'Site Administration' page
        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Site administration', body.text)

        self.fail('Fail...')

Это не позволяет войти в систему, поскольку каким-то образом он не создает действительную учетную запись администратора. Как я могу это сделать с помощью заводского мальчика? Возможно ли, или мне нужно использовать светильники для этого?

(В этом посте некоторые люди предложили светильники, но заводский мальчик не появился: как создать пользователя admin в django tests.py. Я также попытался предложить решение, предложенное внизу в том же ответе: qaru.site/info/232745/.... Это не сработало для меня...)

Ответ 1

Если вы подклассифицируете factory.DjangoModelFactory, он должен сохранить объект пользователя для вас. См. Раздел примечания в разделе PostGenerationMethodCall. Тогда вам нужно только сделать следующее:

class UserFactory(factory.DjangoModelFactory):
    FACTORY_FOR = User

    email = '[email protected]'
    username = 'admin'
    password = factory.PostGenerationMethodCall('set_password', 'adm1n')

    is_superuser = True
    is_staff = True
    is_active = True

Ответ 2

Я предполагаю, что вы работаете над учебником http://www.tdd-django-tutorial.com, потому что там, где я тоже застрял. Вероятно, вы догадались об этом, но для следующего человека, вот код, который работал для меня, трюк заключался в добавлении метода _prepare для обеспечения шифрования пароля и установки всех флагов в true (это было сделано с Django 1.5. 1, если вы используете более раннюю версию, измените импорт модели пользователя)

from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

import factory
from django.contrib.auth import get_user_model
User = get_user_model()


class UserFactory(factory.DjangoModelFactory):
    FACTORY_FOR = User

    email = '[email protected]'
    username = 'admin'
    password = 'adm1n'

    is_superuser = True
    is_staff = True
    is_active = True

    @classmethod
    def _prepare(cls, create, **kwargs):
        password = kwargs.pop('password', None)
        user = super(UserFactory, cls)._prepare(create, **kwargs)
        if password:
            user.set_password(password)
            if create:
                user.save()
        return user

class PollsTest(LiveServerTestCase):

    def setUp(self):
        self.browser = webdriver.Firefox()
        self.browser.implicitly_wait(3)
        self.user = UserFactory.create()


    def tearDown(self):
        self.browser.quit()

    def test_can_create_new_poll_via_admin_site(self):
        self.browser.get(self.live_server_url+'/admin/')

        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Django administration', body.text)

        username_field = self.browser.find_element_by_name('username')
        username_field.send_keys(self.user.username)

        password_field = self.browser.find_element_by_name('password')
        password_field.send_keys('adm1n')
        password_field.send_keys(Keys.ENTER)

        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Site administration', body.text)

        polls_links = self.browser.find_element_by_link_text('Polls')
        self.assertEqual(len(polls_links), 2)


        self.fail('Finish the test!')

Ответ 3

Создание пользователей-администраторов:

Вы можете добавить объявление Params, которое обеспечивает гибкость для быстрого создания пользователя-администратора или обычного пользователя.

https://factoryboy.readthedocs.io/en/latest/introduction.html?highlight=class%20Params#altering-a-factory-s-behaviour-parameters-and-traits

Установка необработанных паролей:

Чтобы гарантировать, что параметр пароля будет установлен как необработанное незашифрованное значение, вы можете использовать Django set_password, чтобы установить необработанный пароль после первоначального сохранения в переопределении метода _create classmethod.

https://docs.djangoproject.com/en/2.1/ref/contrib/auth/#django.contrib.auth.models.User.set_password

class UserFactory(factory.django.DjangoModelFactory):
    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    username = factory.Sequence(lambda n: 'demo-user-%d' % n)
    is_staff = False
    is_superuser = False
    password = 'secret'

    @factory.lazy_attribute
    def email(self):
        return '%[email protected]' % self.username

    class Meta:
        model = User

    class Params: 
        # declare a trait that adds relevant parameters for admin users
        flag_is_superuser = factory.Trait(
            is_superuser=True,
            is_staff=True,
            username = factory.Sequence(lambda n: 'admin-%d' % n),
        )

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        password = kwargs.pop("password", None)
        obj = super(UserFactory, cls)._create(model_class, *args, **kwargs)
        # ensure the raw password gets set after the initial save
        obj.set_password(password)
        obj.save()
        return obj

Использование:

# This admin user can log in as "admin-1", password "secret"
admin = UserFactory.create(flag_is_superuser=True)

# This regular user can log in as "userABC", password "secretABC"
user = UserFactory.create(username="userABC", password="secretABC")

Использование factory-boy v2.11.1 и Django v1.11.6

Ответ 4

У меня была аналогичная проблема при создании пользователя. Django хэш-пароли при создании пользователя, и вы сохраняете пароль с помощью DjangoFactory без хэша. При входе в систему Django проверяет пароль, который вы отправляете с сохраненным хэшем. На этом шаге проверка завершается неудачно, поскольку вы проверяете не хешированный пароль с недопустимым паролем. Вот пример того, как я исправил это в своем коде:

from django.contrib.auth.hashers import make_password
from factory import DjangoModelFactory, Sequence



class UserFactory(DjangoModelFactory):
    class Meta:
        model = User
        django_get_or_create = ('username', 'password')

    username = Sequence(lambda n: 'somename%s' % n)
    password = Sequence(lambda p: 'mysuperpass%s' % p)

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Override the default ''_create'' with our custom call."""
        kwargs['password'] = make_password(kwargs['password'])
        return super(UserFactory, cls)._create(model_class, *args, **kwargs)

Я беру пароль, который был сгенерирован с использованием Sequence и hash, используя метод Django make_password. В тестах вы можете создать var с не хешированным значением и создать пользователя с этим var. Пример:

password = 'test123'
user = UserFactory(password=my_password)

Ответ 5

Вот как я это сделал с Factory Boy 2.7.0 и Django 1.8.4. Ниже представлены две фабрики: одна для базового пользователя и одна для администратора, которая наследует от базового добавления только необходимые поля.

class UserFactory(DjangoModelFactory):

    class Meta:
        model = User
        django_get_or_create = ('username', 'email', 'password')

    username = 'basic'
    email = '[email protected]_admin.com'
    password = 'basicpassword'


class AdminFactory(UserFactory):
    username = 'admin'
    is_superuser = True

Ответ 6

Я использую Django 1.11 (могу поспорить, что он будет работать в Django 2+) и factory_boy 2.11.1. Это было довольно просто:

import factory
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User


class SuperUserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User

    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    username = factory.Faker('email')
    password = factory.LazyFunction(lambda: make_password('pi3.1415'))
    is_staff = True
    is_superuser = True

В этом примере у всех пользователей будет пароль 'pi3.1415' измените его, если вы хотите что-то другое, или вы даже можете использовать password = factory.Faker('password') для генерации случайного пароля (однако, это должно быть что-то Вы можете понять, иначе будет очень трудно войти).

Пример создания суперпользователя

>>> user = SuperUserFactory.create()
>>> user.username # the following output will be different in your case
[email protected]

Используйте адрес электронной почты, полученный от user.username и пароль 'pi3.1415' чтобы войти в систему с user.username администратора.

Что, если у пользователя есть обратные внешние ключи?

Простой, скажем, у вас есть Profile модели, который имеет внешний ключ к вашей модели User. Затем вы должны добавить следующие классы:

class Profile(models.Model):
    user = models.OneToOneField(User)
    visited = models.BooleanField(default=False)


# You need to set the foreign key dependency using factory.SubFactory
class ProfileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Profile

    user = factory.SubFactory(UserFactory)


# use a RelatedFactory to refer to a reverse ForeignKey 
class SuperUserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User

    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    username = factory.Faker('email')
    password = make_password('pi3.1415')
    is_staff = True
    is_superuser = True
    profile = factory.RelatedFactory(ProfileFactory, 'user', visited=True)

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