I'm a relative Django beginner and just started doing some testing for my projects. What I want to do is build a functional test with selenium that logs into the Django Admin site.
I first followed this tutorial http://www.tdd-django-tutorial.com/tutorial/1/ and used fixtures and dumpdata to make the admin account info available for the testing app (which creates a new database). This works fine.
I then wanted to see if I can do the same using factory-boy to replace the fixtures. Factory boy works by instantiating the necessary object within the tests.py file which seems cleaner to me. Somehow I can't get this to work and the Factory_boy documentation is not too helpful...
Here is my 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...')
This fails to log in as somehow it doesn't create a valid admin account. How can I do that using factory-boy? Is it possible or do I need to use fixtures for that?
(In this post some people suggested fixtures are necessary but factory boy didn't come up: How to create admin user in django tests.py. I also tried the solution suggested at the bottom in the same answer: https://stackoverflow.com/a/3495219/1539688. It didn't work for me...)
If you subclass factory.DjangoModelFactory it should save the user object for you. See the note section under PostGenerationMethodCall. Then you only need to do the following:
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
I am using Django 1.11 (I can bet it will work in Django 2+) and factory_boy 2.11.1. This was pretty simple:
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
In this example, all users will have password 'pi3.1415'
change it accordingly if you want something different, or you can even use password = factory.Faker('password')
to generate a random password (however, it should be something you are able to figure out. Otherwise, it will be very hard to log in).
>>> user = SuperUserFactory.create() >>> user.username # the following output will be different in your case [email protected]
Use the email you got from user.username
and the password 'pi3.1415'
to log in in the admin.
Simple, let's say you have a model Profile
which has a foreign key to your User
model. Then you have to add the following classes:
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)
That's it, use the same logic in the example to create your superuser.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With