[Python][Django] django.test.TestCaseクラスのassertRedirectsメソッドは、ドメイン名を検査しない。

環境

この記事の内容は、Ubuntu Linux 6.10, Python 2.4.4c1, Django 0.97-pre-SVN-6097で確認しました。

問題点

以下のテストケースが、失敗します。

from django.http import HttpResponseRedirect
from django.test import TestCase

class TestFoo(TestCase):

    def test_redirect(self):
        response = HttpResonseRedirect("http://example.com/")

        self.assertRedirects(response, "http://example.com/")

原因

django.test.TestCaseクラスのassertRedirectsメソッドが、リダイレクト先のドメイン名まで検査してないことが原因です。

対策

以下のようにassertRedirectsメソッドを書き換えます。

        self.failUnlessEqual("http://example.com/", response["Location"])

詳細

問題のassertRedirectsメソッドは、以下のような実装になっています。

    def assertRedirects(self, response, expected_url, status_code=302,
                        target_status_code=200):
        """Asserts that a response redirected to a specific URL, and that the
        redirect URL can be loaded.

        Note that assertRedirects won't work for external links since it uses
        TestClient to do a request.
        """
        self.assertEqual(response.status_code, status_code,
            ("Response didn't redirect as expected: Response code was %d"
             " (expected %d)" % (response.status_code, status_code)))
        scheme, netloc, path, query, fragment = urlsplit(response['Location'])
        url = path
        if query:
            url += '?' + query
        if fragment:
            url += '#' + fragment
        self.assertEqual(url, expected_url,
            "Response redirected to '%s', expected '%s'" % (url, expected_url))
        :

問題となるのは、以下のコードです。

        scheme, netloc, path, query, fragment = urlsplit(response['Location'])
        url = path
        if query:
            url += '?' + query
        if fragment:
            url += '#' + fragment
        self.assertEqual(url, expected_url,
            "Response redirected to '%s', expected '%s'" % (url, expected_url))

リダイレクト先 (response['Location']) を、urlparse.urlsplit関数でスキーマやドメイン名などに分解していますが、検査対象になっているのはパスから先だけです。このため、リダイレクト先が"http://example.com/"だったとしても、比較されるのは"/"だけであり、"http://example.com/"と比較しても失敗します。