我是Django的初学者,刚开始为我的项目做一些测试。我想要做的是用selenium构建一个功能测试,登录到Django Admin站点。
我首先遵循本教程http://www.tdd-django-tutorial.com/tutorial/1/并使用fixtures和dumpdata来为测试应用程序(创建新数据库)提供管理员帐户信息。这很好。
然后我想看看我是否可以使用factory-boy来替换灯具。工厂男孩通过在tests.py文件中实例化必要的对象来工作,这对我来说似乎更干净。不知怎的,我无法让这个工作,Factory_boy文档不太有用......
这是我的tests.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...')
无法以某种方式登录,因为它无法创建有效的管理员帐户。我怎么能用工厂男孩那样做?有可能或者我需要使用固定装置吗?
(在这篇文章中,有些人建议使用固定装置,但工厂男孩没有出现:How to create admin user in django tests.py。我也在同一个答案的底部尝试了解决方案:https://stackoverflow.com/a/3495219/1539688。它没有对我有用......)
答案 0 :(得分:37)
如果你继承了factory.DjangoModelFactory,它应该为你保存用户对象。请参阅PostGenerationMethodCall下的注释部分。然后您只需要执行以下操作:
class UserFactory(factory.DjangoModelFactory):
FACTORY_FOR = User
email = 'admin@admin.com'
username = 'admin'
password = factory.PostGenerationMethodCall('set_password', 'adm1n')
is_superuser = True
is_staff = True
is_active = True
答案 1 :(得分:7)
我假设你正在研究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 = 'admin@admin.com'
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!')
答案 2 :(得分:2)
创建管理员用户:
您可以添加一个Params声明,该声明提供了快速创建管理员用户或普通用户的灵活性。
设置原始密码:
为了确保将密码参数设置为未加密的原始值,可以在_create类方法重写中进行初始保存之后,使用Django的set_password设置原始密码。
https://docs.djangoproject.com/en/2.1/ref/contrib/auth/#django.contrib.auth.models.User.set_password
80
用法:
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 '%s@test.com' % 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
使用factory-boy v2.11.1和Django v1.11.6
答案 3 :(得分:1)
创建用户时遇到了类似的问题。创建用户时使用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生成的密码并使用Django make_password
方法对其进行哈希处理。在测试中,您可以使用非散列值创建var,并使用此var创建用户。
例如:
password = 'test123'
user = UserFactory(password=my_password)
答案 4 :(得分:1)
我正在使用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
amber60@hotmail.com
使用从user.username
获得的电子邮件和密码'pi3.1415'
登录管理员。
简单,假设您有一个模型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 = factory.LazyFunction(lambda: make_password('pi3.1415'))
is_staff = True
is_superuser = True
profile = factory.RelatedFactory(ProfileFactory, 'user', visited=True)
就是这样,在示例中使用相同的逻辑来创建您的超级用户。
答案 5 :(得分:0)
这样,我认为您可以保留代码中期望的行为,这样就可以为密码设置一个默认值,也可以在调用UserFactory时将其替换为所需的任何值。
class UserFactory(factory.Factory):
FACTORY_FOR = User
username = 'jeff'
password = 'pass'
is_superuser = True
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Create an instance of the model, and save it to the database."""
if cls._meta.django_get_or_create:
return cls._get_or_create(model_class, *args, **kwargs)
manager = cls._get_manager(model_class)
return manager.create_user(*args, **kwargs) # Just user the create_user method recommended by Django