今回の内容
前回はDjango 2.0での変更点を取り上げ、モデルの定義、Django REST frameworkの導入ついて解説しました。前回までのコードは以下から取得できます。
第3回となる今回は、まず前回実装したViewに対するテストを取り上げます。Djangoの標準的なテストから始めて、サードパーティを利用したより実践的なテストの書き方を紹介します。その次に、実装したテストをCircleCIでの継続的インテグレーションに組み込みます。
テストの作成
前回Django REST frameworkのModelViewSetを用いて実装したkanban/board/views.py
の品質を担保するために、テストを書いてみましょう。
python manage.py startapp
を実行した際にtests.py
というテスト用のファイルが作成されているので、まずはそこにテストを書いていきます。
TestCase
DjangoではPython標準のunittest.TestCase
を拡張したものであるdjango.test.TestCaseが用意されています。次の図は、unittestとDjangoの各TestCase間の継承関係を表したものです。
django.test.TestCase
には、Djangoアプリケーションのテストを書くうえで役立つ機能が以下のように数多く備わっています。
- フィクスチャ読み込みによるテストデータ生成
- settingsの上書き機能
- 独自のアサーションメソッド
- タギングによるテストの分類
- メール送信をダミーの送信箱に振り分け
- 各テストを実行する度にDBをロールバック
それでは、データをPOSTしてチケットが正常に作成されるかを確かめるテストを書いてみます。
import json from django.test import TestCase from django.urls import reverse from rest_framework import status from kanban.board.models import Ticket class TicketTests(TestCase): def test_post(self): url = reverse('ticket-list') data = { 'assignee': None, 'name': 'test ticket', 'description': 'This is a test ticket.', 'status': 1, 'start': '2018-06-01', 'end': None, } response = self.client.post(url, json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Ticket.objects.count(), 1) self.assertEqual(Ticket.objects.get().name, 'test ticket')
django.test.TestCase
のself.client
はデフォルトで、django.test.Clientのインスタンスが格納されています。django.test.Client
とは、ダミーのブラウザのように振る舞い、DjangoのHTTP関連のテストを助けるものです。
self.client.post(url, json.dumps(data), 'application/json')
とすることで、http://localhost:8000/api/tickets/に向けて、以下のJSONをPOSTできます。
{ "assignee": null, "name": "test ticket", "description": "This is a test ticket.", "status": 1, "start": "2018-06-01", "end": null }
self.assertEqual()
を使って、以下の観点から期待した値かどうかをチェックしています。
- ステータスコードが201かどうか
- 作成されたレコードが1つかどうか
- 作成されたチケットのname属性が正しいかどうか
ここでは1つのテストケースに複数のassertを実行していますが、途中のアサーションで失敗するとそれ以降のアサーションは実行されません。この方式とは別に、テストケース毎に1つのアサーション(one assertion per test)で実装するやり方もあります。この方式の利点は、どのデータが原因でテストが失敗しているのかわかりやすくなる点や、どのテストケースが落ちているかを正しくレポートできる点にあります。
テストの実行には、python manage.py test <ラベル名>
コマンドを使います。
(env) $ python manage.py test kanban Creating test database for alias 'default'... System check identified no issues (0 silenced). . ---------------------------------------------------------------------- Ran 1 test in 0.066s OK
python manage.py test
の引数には、Pythonのモジュールなどを指定するようになっています。以下のようにテストケースやテストメソッドを指定することで、実行したいテストの範囲を絞ることも可能です。今のところテストメソッドは1つしか実装していないため、以下の4つはすべて同じ振る舞いになります。
- python manage.py test kanban
- python manage.py test kanban.board
- python manage.py test kanban.board.tests.TicketTests
- python manage.py test kanban.board.tests.TicketTests.test_post