71

django の単体テストをどのように設計する必要があるかを理解するのに問題があります。

私の理解では、ビュー全体を一度にテストすることは不可能に思えます。リクエストの pre-post 状態と post 状態を区別する必要があります。しかし、私はこれを設計する方法がわかりません。実際の例はありますか?

ドキュメントを見ると、例が単純化されすぎており、モデルのみに焦点が当てられています。

@login_required
def call_view(request, contact_id):
    profile = request.user.get_profile()
    if request.POST:        
        form = CallsForm(profile.company, request.POST)           
        if form.is_valid()
        return HttpResponseRedirect('/contact/' + contact_id + '/calls/')
    else:        
        form = CallsForm(profile.company, instance=call)              
    variables = RequestContext(request, {'form':form}
    return render_to_response('conversation.html', variables)

アップデート:

成功テストを機能させようとしていますが、それでも失敗します:

def test_contact_view_success(self):
    # same again, but with valid data, then
    self.client.login(username='username1', password='password1')
    response = self.client.post('/contact/add/', {u'last_name': [u'Johnson'], }) 
    self.assertRedirects(response, '/')

エラーメッセージ:

AssertionError: Response didn't redirect as expected: Response code was 200 (expected 302)

これは、 form.is_valid() が失敗してリダイレクトされないためだと思いますよね?

4

2 に答える 2

117

NBNB! これは厳密には「単体テスト」ではありません。Django ビュー コードの独立した単体テストを作成することは困難であり、一般的ではありません。これは統合テストのようなものです...

あなたの見解にはいくつかの経路があることは正しいです:

  1. GETまたはPOST匿名ユーザーによる (ログイン ページにリダイレクトする必要があります)
  2. GETまたはPOSTプロファイルのないログイン ユーザーによる (UserProfile.DoesNotExist例外を発生させる必要があります)
  3. GETログインしたユーザーによる (フォームを表示する必要があります)
  4. POST空白のデータを持つログイン ユーザーによる (フォーム エラーを表示する必要があります)
  5. POST無効なデータを持つログイン ユーザーによる (フォーム エラーを表示する必要があります)
  6. POST有効なデータを持つログイン ユーザーによる (リダイレクトする必要があります)

テスト1は実際には単にテスト@login_requiredしているだけなので、スキップできます。とにかくテストする傾向があります(そのデコレータを使用するのを忘れた場合に備えて)。

2のエラー ケース (500 エラー ページ)が本当に必要なものかどうかわかりません。代わりに何をしたいのかを考え出すか (おそらくを使用するget_or_create()か、例外をキャッチしてDoesNotExistその方法で新しいプロファイルを作成します)、ユーザーがプロファイルを作成するためのページにリダイレクトします。

カスタム検証の程度によっては、4を実際にテストする必要がない場合があります。

いずれにせよ、上記のすべてを考えると、私は次のようにします:

from django.test import TestCase

class TestCalls(TestCase):
    def test_call_view_deny_anonymous(self):
        response = self.client.get('/url/to/view', follow=True)
        self.assertRedirects(response, '/login/')
        response = self.client.post('/url/to/view', follow=True)
        self.assertRedirects(response, '/login/')

    def test_call_view_load(self):
        self.client.login(username='user', password='test')  # defined in fixture or with factory in setUp()
        response = self.client.get('/url/to/view')
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'conversation.html')

    def test_call_view_fail_blank(self):
        self.client.login(username='user', password='test')
        response = self.client.post('/url/to/view', {}) # blank data dictionary
        self.assertFormError(response, 'form', 'some_field', 'This field is required.')
        # etc. ...

    def test_call_view_fail_invalid(self):
        # as above, but with invalid rather than blank data in dictionary

    def test_call_view_success_invalid(self):
        # same again, but with valid data, then
        self.assertRedirects(response, '/contact/1/calls/')

明らかに、ここでの欠点はハードコードされた URL です。テストで使用するreverse()か、(URL ではなく) メソッドとしてビューを使用してリクエストを構築することができます。RequestFactoryただし、後者の方法では、ハードコードされた値を使用するかreverse()、リダイレクト ターゲットをテストする必要があります。

お役に立てれば。

于 2012-08-09T15:57:28.060 に答える
9

Djangoには、完全な要求/応答サイクルをテストするために使用できるテストクライアントが付属しています。ドキュメントには、特定のURLに対してget要求を行い、ステータスコードとテンプレートコンテキストをアサートする例が含まれています。また、POSTを実行し、期待どおりに正常なリダイレクトをアサートするテストも必要になります。

于 2012-08-09T15:25:38.207 に答える