How Can You Create an Admin User with Factory_Boy?

Brian Fabian Crain picture Brian Fabian Crain · Mar 25, 2013 · Viewed 9.2k times · Source

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...)

Answer

emispowder picture emispowder · Jul 31, 2013

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