サーチ…


テスト - 完全な例

これは、新しいDjangoプロジェクトの開始に関するドキュメントを読んだことを前提としています。プロジェクトのメインアプリケーションの名前がtd(テスト駆動の略)であると仮定します。最初のテストを作成するには、test_view.pyという名前のファイルを作成し、次の内容をコピーしてコピーします。

from django.test import Client, TestCase

class ViewTest(TestCase):

    def test_hello(self):
        c = Client()
        resp = c.get('/hello/')
        self.assertEqual(resp.status_code, 200)

このテストは、

 ./manage.py test

それは最も自然に失敗するでしょう!次のようなエラーが表示されます。

Traceback (most recent call last):
  File "/home/me/workspace/td/tests_view.py", line 9, in test_hello
    self.assertEqual(resp.status_code, 200)
AssertionError: 200 != 404

なぜそれが起こるのですか?私たちはそれについてのビューを定義していないので!だからそれをやりましょう。 views.pyという名前のファイルを作成し、次のコードを配置します

from django.http import HttpResponse
def hello(request):
    return HttpResponse('hello')

次に、次のようにurls pyを編集して/ hello /にマップします:

from td import views

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/', views.hello),
    ....
]

テストをもう一度やり直して./manage.py test again and viola !!

Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK

Djangoモデルを効果的にテストする

クラスを想定する

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=50)
   
    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return reverse('view_author', args=[str(self.id)])


class Book(models.Model):
    author = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    private = models.BooleanField(default=false)
    publish_date = models.DateField()

    def get_absolute_url(self):
        return reverse('view_book', args=[str(self.id)])
    
    def __str__(self):
        return self.name

テスト例

from django.test import TestCase
from .models import Book, Author

class BaseModelTestCase(TestCase):

    @classmethod
    def setUpClass(cls):
        super(BaseModelTestCase, cls).setUpClass()
        cls.author = Author(name='hawking')
        cls.author.save()
        cls.first_book = Book(author=cls.author, name="short_history_of_time")
        cls.first_book.save()
        cls.second_book = Book(author=cls.author, name="long_history_of_time")
        cls.second_book.save()


class AuthorModelTestCase(BaseModelTestCase):
    def test_created_properly(self):
         self.assertEqual(self.author.name, 'hawking')
         self.assertEqual(True, self.first_book in self.author.book_set.all())
    
    def test_absolute_url(self):
        self.assertEqual(self.author.get_absolute_url(), reverse('view_author', args=[str(self.author.id)]))

class BookModelTestCase(BaseModelTestCase):
    
    def test_created_properly(self:
        ...
        self.assertEqual(1, len(Book.objects.filter(name__startswith='long'))
    
    def test_absolute_url(self):
        ...

いくつかの点

  • created_properlyテストは、djangoモデルの状態プロパティを検証するために使用されます。それらは、デフォルト値、file_upload_pathsなどを変更した場所のキャッチアップに役立ちます。
  • absolute_urlは自明ではないかもしれませんが、URLパスを変更するとバグを防ぐことができました
  • 私は同様にモデル内で実装されたすべてのメソッドのテストケースを記述します( mockオブジェクトなどを使用して)
  • 共通のBaseModelTestCaseを定義することで、適切なテストを確実に行うためにモデル間に必要な関係を設定することができます。

最後に、疑わしいときは、テストを書く。軽微な動作の変化は細部に注意を払うことによって捕らえられ、長く忘れたコードは不要なトラブルを引き起こすことはありません。

Djangoビューでのアクセス制御のテスト

tl; dr :2つのユーザーオブジェクト( useranother_user )を定義する基本クラスを作成します。他のモデルを作成し、3つのClientインスタンスを定義します。

  • self.client :ブラウザにログインしているuser表す
  • self.another_clientanother_userのクライアントを表す
  • self.unlogged_client :未ログインの人を表す

これらの3つのクライアントオブジェクトからすべてのあなたの公開URLと私的URLにアクセスし、あなたが期待する応答を指示します。以下では、 private (少数の特権ユーザーが所有)またはpublic (誰でも見ることができる)のいずれかのBookオブジェクトの戦略を紹介しました。

from django.test import TestCase, RequestFactory, Client
from django.core.urlresolvers import reverse

class BaseViewTestCase(TestCase):

    @classmethod
    def setUpClass(cls):
        super(BaseViewTestCase, cls).setUpClass()
        cls.client = Client()
        cls.another_client = Client()
        cls.unlogged_client = Client()
        cls.user = User.objects.create_user(
                'dummy',password='dummy'
                )
        cls.user.save()
        cls.another_user = User.objects.create_user(
                'dummy2', password='dummy2'
                )
        cls.another_user.save()
        cls.first_book = Book.objects.create(
                name='first',
                private = true
        )
        cls.first_book.readers.add(cls.user)
        cls.first_book.save()
        cls.public_book = Template.objects.create(
                name='public',
                private=False
        )
        cls.public_book.save()


    def setUp(self):
        self.client.login(username=self.user.username, password=self.user.username)
        self.another_client.login(username=self.another_user.username, password=self.another_user.username)


"""
   Only cls.user owns the first_book and thus only he should be able to see it.
   Others get 403(Forbidden) error
"""
class PrivateBookAccessTestCase(BaseViewTestCase):
    
    def setUp(self):
        super(PrivateBookAccessTestCase, self).setUp()
        self.url = reverse('view_book',kwargs={'book_id':str(self.first_book.id)})

    def test_user_sees_own_book(self):
        response = self.client.get(self.url)
        self.assertEqual(200, response.status_code)
        self.assertEqual(self.first_book.name,response.context['book'].name)
        self.assertTemplateUsed('myapp/book/view_template.html')

    def test_user_cant_see_others_books(self):
        response = self.another_client.get(self.url)
        self.assertEqual(403, response.status_code)
        
    def test_unlogged_user_cant_see_private_books(self):
        response = self.unlogged_client.get(self.url)
        self.assertEqual(403, response.status_code)

"""
    Since book is public all three clients should be able to see the book
"""
 class PublicBookAccessTestCase(BaseViewTestCase):
    
    def setUp(self):
        super(PublicBookAccessTestCase, self).setUp()
        self.url = reverse('view_book',kwargs={'book_id':str(self.public_book.id)})

    def test_user_sees_book(self):
        response = self.client.get(self.url)
        self.assertEqual(200, response.status_code)
        self.assertEqual(self.public_book.name,response.context['book'].name)
        self.assertTemplateUsed('myapp/book/view_template.html')

    def test_another_user_sees_public_books(self):
        response = self.another_client.get(self.url)
        self.assertEqual(200, response.status_code)
        
    def test_unlogged_user_sees_public_books(self):
        response = self.unlogged_client.get(self.url)
        self.assertEqual(200, response.status_code)

データベースとテスト

Djangoはテスト時に特別なデータベース設定を使用して、テストでデータベースを正常に使用できるようにしますが、デフォルトでは空のデータベースで実行します。あるテストでのデータベースの変更は、別のテストでは認識されません。たとえば、次の両方のテストが合格します。

from django.test import TestCase
from myapp.models import Thing

class MyTest(TestCase):

    def test_1(self):
        self.assertEqual(Thing.objects.count(), 0)
        Thing.objects.create()
        self.assertEqual(Thing.objects.count(), 1)

    def test_2(self):
        self.assertEqual(Thing.objects.count(), 0)
        Thing.objects.create(attr1="value")
        self.assertEqual(Thing.objects.count(), 1)

備品

複数のテストでデータベースオブジェクトを使用する場合は、テストケースのsetUpメソッドでデータベースオブジェクトを作成するか、さらに、djangoプロジェクトでフィクスチャを定義した場合は、以下のようにフィクスチャを組み込むことができます:

class MyTest(TestCase):
    fixtures = ["fixture1.json", "fixture2.json"]

デフォルトでは、djangoは各アプリのfixturesディレクトリにあるfixturesチャを探しています。さらにディレクトリはFIXTURE_DIRS設定を使って設定できます:

# myapp/settings.py
FIXTURE_DIRS = [
    os.path.join(BASE_DIR, 'path', 'to', 'directory'),
]

次のようにモデルを作成したとします。

# models.py
from django.db import models


class Person(models.Model):
    """A person defined by his/her first- and lastname."""
    firstname = models.CharField(max_length=255)
    lastname = models.CharField(max_length=255)

それで、あなたの.jsonのフィクスチャは次のようになります:

# fixture1.json
[
    { "model": "myapp.person",
        "pk": 1,
        "fields": {
            "firstname": "Peter",
            "lastname": "Griffin"
        }
    },
    { "model": "myapp.person",
        "pk": 2,
        "fields": {
            "firstname": "Louis",
            "lastname": "Griffin"
        }
    },
]

テストデータベースを再利用する

テスト実行のスピードを上げるために、管理コマンドにテストデータベースを再利用するよう指示することができます(また、テスト実行のたびに作成されたり削除されることを防ぐため)。これは、以下のようにkeepdb(またはshorthand -k )フラグを使って行うことができます:

# Reuse the test-database (since django version 1.8)
$ python manage.py test --keepdb

実行されるテストの数を制限する

テストランナーがどのモジュールを発見するべきかを指定することによって、 manage.py testによって実行されるテストを制限することができます:

# Run only tests for the app names "app1"
$ python manage.py test app1

# If you split the tests file into a module with several tests files for an app
$ python manage.py test app1.tests.test_models

# it's possible to dig down to individual test methods.
$ python manage.py test app1.tests.test_models.MyTestCase.test_something

たくさんのテストを実行したい場合は、ファイル名のパターンを渡すことができます。たとえば、モデルに関係するテストのみを実行するとします。

$ python manage.py test -p test_models*
Creating test database for alias 'default'...
.................................................
----------------------------------------------------------------------
Ran 115 tests in 3.869s

OK

最後に、-- --failfastを使用して、最初の失敗時にテストスイートを停止することができます。この引数を指定すると、スイートで発生した潜在的なエラーを素早く取得できます。

$ python manage.py test app1
...F..
----------------------------------------------------------------------
Ran 6 tests in 0.977s

FAILED (failures=1)


$ python manage.py test app1 --failfast
...F
======================================================================
[Traceback of the failing test]
----------------------------------------------------------------------
Ran 4 tests in 0.372s

FAILED (failures=1)


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow