Search code examples
pythondjangodjango-testing

Wrong Behaviour doing tests on Django


I'm having problems to do test on Django. I've been reading the documentation of the responses and I can't do the same as they explain on the documentation.

When I get the response, I only have access to response.status_code and can't access to context or redirect_chain when I write response.(and now PyCharm shows all available options).

I've checked on settings.py and I've 'BACKEND': 'django.template.backends.django.DjangoTemplates' to be sure that I'm using Django templates so I don't know why don't work the test. I need configure something?

The code of the test I'm trying to do it's:

from django.test import TestCase
from django.test.client import Client


class Test(TestCase):
    def testLogin(self):
        client = Client()
        headers = {'X-OpenAM-Username': 'user', 'X-OpenAM-Password': 'password', 'Content-Type': 'application/json'}
        data = {}
        response = self.client.post('/login/', headers=headers, data=data, secure=True, follow=True)
        assert (response.status_code == 200)
        # self.assertRedirects(response, '/menu/', status_code=301, target_status_code=200)

I'm not using Django authentication, the login form sends the data to an IDP and if the IDP sends with a correct answer, the "login" it's successful:

def login(request):
    logout(request)
    message = None
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            username = request.POST['username']
            password = request.POST['password']
            headers = {'X-OpenAM-Username': username, 'X-OpenAM-Password': password, 'Content-Type': 'application/json'}
            data = {}
            req = requests.post('http://openam.idp.com:8090/openamIDP/json/authenticate', headers=headers, params=data)
            if req.status_code == 200:
                    respJson = json.loads(req.content)
                    tokenIdJson = respJson['tokenId']
                    request.session['tokenId'] = tokenIdJson
                    return render_to_response('menu/menu.html', request)
            elif req.status_code == 401:
                message = "Invalid username and/or password. Please, try again"
    else:
        form = LoginForm()
    return render_to_response('registration/login.html', {'message': message, 'form': form},
                             context_instance=RequestContext(request)) 

The redirect assert it's commented because now it fails, when I do the debug I see an empty redirect_chain. I don't understand why happens this because running the web everything works, all views redirect as expected.

Why I only can check status_code? I'm doing something wrong when I redirect after a successful login that on a normal use it works but on the test not?

Thanks.


Solution

  • The remote authentication url expects the credentials as headers, but your local login view expects them as POST data. Your test passes the credentials as headers to your local view.

    As a result, the form is passed an empty dictionary (request.POST contains no actual data), and the form is invalid. You get an empty form as a response, without any redirects.

    You have to simply pass the credentials as post data to your local view:

    def testLogin(self):
        client = Client()
        data = {'username': 'user', 'password': 'password'}
        response = self.client.post('/login/', data=data, secure=True, follow=True)
        assert (response.status_code == 200)
        self.assertRedirects(response, '/menu/', status_code=301, target_status_code=200)