title: How to test login process?
body: <p>I am developing a web application using Django 1.6 where I require users to log in using my login form. I want to write a test case that tests the procedure of a user logging in. </p>
  
  <p>I did succeed to get a working login page, meaning I was able to log in. The following steps explain my setup. Writing a test case for this procedure did however fail. At this point I'm neither able to spot an error in my test, nor sure whether this approach makes sense before all. Can someone help me?</p>
  
  <p><strong>Update:</strong> In the meantime I have noticed, that my form error message was too unspecific. The issue appears to be caused by empty form fields that fail some form validation step. When I add the errors <code>{{ form.errors }}</code> to the template, the response contains the following (formatted a little less nicely):</p>
  
  <pre><code>&lt;ul class="errorlist"&gt;
    &lt;li&gt;username
      &lt;ul class="errorlist"&gt;
        &lt;li&gt;This field is required.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;password
      &lt;ul class="errorlist"&gt;
        &lt;li&gt;This field is required.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  </code></pre>
  
  <p>I'm still not sure how to test this procedure most reasonably. I'm quite new to Django and the philosophy of it's testing framework. May it be, that this issue falls not directly into the scope of the Django testing framework, where models, and views, and forms are (seemingly) intended to be tested rather seperated from each other? Does this test rather fall into the realm of an independent test suite doing black-box/functional testing, e.g., using Selenium?</p>
  
  <hr>
  
  <p>I started like this:</p>
  
  <ol>
  <li><p>Started a fresh project, like this:</p>
  
  <pre><code>django-admin.py startproject login_test
  </code></pre></li>
  <li><p>added an entry to the <code>login_test/urls.py</code>, like this:</p>
  
  <pre><code>urlpatterns = patterns('',
      url(r'^login/$', 'django.contrib.auth.views.login'),
      url(r'^admin/', include(admin.site.urls)),
  )
  </code></pre></li>
  <li><p>made up a template at <code>/home/moooeeeep/login_test/templates/registration/login.html</code>, like this:</p>
  
  <pre><code>{% if form.errors %}
  &lt;p&gt;Your username and password didn't match. Please try again.&lt;/p&gt;
  {% endif %}
  {% if not user.is_active %}
  &lt;form method="post" action="{% url 'django.contrib.auth.views.login' %}"&gt;
    {% csrf_token %}
    {{ form.as_p }}
    &lt;button type="submit"&gt;Login&lt;/button&gt;
    &lt;input type="hidden" name="next" value="{% url 'django.contrib.auth.views.login' %}" /&gt;
  &lt;/form&gt;
  {% else %}
  &lt;p&gt;You are logged in as &lt;strong&gt;{{ user.username }}&lt;/strong&gt;.&lt;/p&gt;
  {% endif %}
  </code></pre></li>
  <li><p>added the template directory to the <code>TEMPLATE_DIRS</code> in the <code>login_test/settings.py</code>, like this:</p>
  
  <pre><code>TEMPLATE_DIRS = (
      '/home/moooeeeep/login_test/templates/',
  )
  </code></pre></li>
  <li><p>Sync'ed the database to get the auth-related tables, and added a superuser like this:</p>
  
  <pre><code>python manage.py syncdb
  </code></pre></li>
  </ol>
  
  <p>If I did not miss a step, at this point I am able to log into my site. When logged in I get displayed my username, if not I see the form, if login fails it displays an error message in addition.</p>
  
  <hr>
  
  <p>My test case however, after submitting correct post data, gets to see the failed login response, with the user not being logged in. </p>
  
  <p>Here's my <code>login_test/tests.py</code>: </p>
  
  <pre><code>from django.contrib.auth.models import User
  from django.contrib.auth import SESSION_KEY
  from django.test import TestCase
  
  class LogInTest(TestCase):
      def setUp(self):
          self.credentials = {
              'username': 'testuser',
              'password': 'secret'}
          User.objects.create_user(**self.credentials)
      def test_login(self):
          # login
          response = self.client.post('/login/', **self.credentials)      
          # should be logged in now, fails however
          self.assertTrue(response.context['user'].is_active)
  </code></pre>
  
  <p>Here's the output:</p>
  
  <pre><code>$ python manage.py test
  Creating test database for alias 'default'...
  F
  ======================================================================
  FAIL: test_login (login_test.tests.LogInTest)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "/home/moooeeeep/login_test/login_test/tests.py", line 16, in test_login
      self.assertTrue(response.context['user'].is_active)
  AssertionError: False is not true
  
  ----------------------------------------------------------------------
  Ran 1 test in 0.008s
  
  FAILED (failures=1)
  Destroying test database for alias 'default'...
  </code></pre>
  
  <hr>
  
  <p>Here's my <code>login_test/settings.py</code>:</p>
  
  <pre><code>import os
  BASE_DIR = os.path.dirname(os.path.dirname(__file__))
  # SECURITY WARNING: keep the secret key used in production secret!
  SECRET_KEY = '+6e-6t8dnl$75fx%=7y$+4ipo&amp;i=kvw(p*963p37)7o$1-)30u'
  # SECURITY WARNING: don't run with debug turned on in production!
  DEBUG = True
  TEMPLATE_DEBUG = True
  INSTALLED_APPS = (
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
  )
  MIDDLEWARE_CLASSES = (
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
  )
  ROOT_URLCONF = 'login_test.urls'
  WSGI_APPLICATION = 'login_test.wsgi.application'
  DATABASES = {
      'default': {
      'ENGINE': 'django.db.backends.sqlite3',
      'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
      }
  }
  TEMPLATE_DIRS = (
      '/home/moooeeeep/login_test/templates/',
  )
  </code></pre>