2012/05/07(月)Djangoアプリケーションの運用時とテスト時で認証バックエンドを切り替える

2012/05/07 22:50

仰々しいタイトルをつけるほどのテクニックでもないんですが、メモ書きとして残しておきます。

私は今、DjangoにTwingo *1 という自作の認証バックエンドを乗せてシステムを構築している最中なのですが、単体テスト時にDjango本体のテストが通らない事象が発生しました。最初は私のsetting.pyの書き方が悪かったのかと思ったのですが、調べてみると、どうもDjango本体のテストコードが標準のバックエンド以外のことを考慮していないのが原因のようです。

#13394 (django.contrib.auth.tests fail with custom Authentication Backends) – Django
https://code.djangoproject.com/ticket/13394

パッチファイルもあるにはあるんですが、以前のバージョンに対するものなので、1.4には上手く当たってくれません。これは困ったなぁ……と思ったものの、冷静に考えてみればsetting.pyは単なる設定ファイルというよりはPythonプログラムです。じゃあif文で分岐させればいいんじゃね?

if not 'test' in sys.argv:
AUTHENTICATION_BACKENDS = (
'twingo.backends.TwitterBackend',
)

本当は引数をきっちりチェックしたほうがいいんでしょうが、設定ファイルにあまり長いロジックを書きたくないのでこんな手抜きな感じで。アプリケーション名がtestだったりしない限りはこれで大丈夫なはずです。

こういう設定にすることにより、ログインが必要なページのテストがやりやすくなるという副産物もあります。通常の実行時は独自のバックエンドを動かすとしても、テスト時はあくまでも通常の認証方式なので、認証行為そのものはテストユーザーを突っ込んでself.client.login()を呼ぶだけで良くなります。

class AuthTest(TestCase):
def test_auth(self):
User.objects.create_user('user', 'user@example.com', 'user-password')
self.client.login(username='user', password='user-password')
response = self.client.get('/auth/')
# 以下assert文が続く

テストコード中でTwitter連携をした上で認証するのは至難の業なので、これでずいぶん楽にテストができるようになりました。

*1:https://github.com/7pairs/Twingo