概要
- djangoのテストフレームワークでAPIキーを使用したPOSTリクエストのテストケースを作成しました。ヘッダーの
HTTP_
プレフィックスとテストクライアントのpost
メソッドの引数headers
あたりで詰まったところも調べてまとめておきましたので、これからAPIテスト作る方のご参考となればと思います。
前提
- Python:3.6.15
- Django:3.0.5
APIのテストケース(サンプルコード)
- 以下が
HTTP_X-API-KEY
を使用したDjangoのサンプルコードです。- 正しいAPIキーは
SAMPLE_API_KEY
とします。 - 間違ったAPIキーを
WRONG_API_KEY
とします。
- 正しいAPIキーは
- 以下のテストケースでは、正しいAPIキーと間違ったAPIキーを使用してリクエストを送信し、レスポンスのステータスコードを検証しています。
from django.test import TestCase
class ApiTestCase(TestCase):
def test_post_sample_with_api_key(self):
headers = {'HTTP_X_API_KEY': 'SAMPLE_API_KEY'}
data = {'key': 'value'}
response = self.client.post('/api/', data=data, follow=True, content_type='application/json', accept='application/json', **headers)
self.assertEqual(response.status_code, 200)
def test_sample_without_api_key(self):
headers = {'HTTP_X_API_KEY': 'WRONG_API_KEY'}
data = {'key': 'value'}
response = self.client.post('/api/', data=data, follow=True, content_type='application/json', accept='application/json', **headers)
self.assertEqual(response.status_code, 401)
リクエストヘッダーについて
- ①ヘッダー名に
HTTP_
プレフィックスをつける必要がある - ②
headers
はpost
のキーワード引数として指定する必要がある - ③そのほかのヘッダー部分の説明
①ヘッダー名にHTTP_
プレフィックスをつける必要がある
- ちょっと詰まったのが、リクエストヘッダーの
X-API-KEY
です。APIのHTTPリクエストにはヘッダーとボディがありますが、X-API-KEY
はヘッダー部分になります。 -
HTTP_
プリフィックスは、HTTPリクエストヘッダーのキーを指定するために使用されます。Djangoのテストクライアントでは、ヘッダーをキーワード引数として渡す場合に、ヘッダー名にHTTP_
プリフィックスを付ける必要があるのです。これがわからずに以下のように記載していたのですが、全然成功しないので結構詰まりました。
headers = {'X_API_KEY': 'SAMPLE_API_KEY'}
-
HTTP_
プリフィックスは、Djangoのテストクライアントが実際のHTTPリクエストをシミュレートするために、環境変数としてヘッダーを設定しているかららしい。確かに以下のサイトを見てもUSER_AGENT
などにHTTP_
プリフィックスを付けていますね。 - この辺はあまり記事がないように感じました。以下が近かったです。
②headers
はpost
のキーワード引数として指定する必要がある
-
**headers
は辞書として定義されたキーワード引数を展開するPythonの構文で、上記の場合は以下のような形で展開されます。
self.client.post('/api/', data=data, follow=True, content_type='application/json', accept='application/json', HTTP_X_API_KEY='SAMPLE_API_KEY')
- この
headers
と先述のHTTP_
が相まって詰まりました。というのも、**headers
であれば成功しましたがheaders=headers
だと失敗してしまったからです。Djangoのテストクライアントのpost
メソッドでは、引数にキーワード引数を利用する必要があるのです。以下が公式ドキュメントからの引用です。
It requires no arguments at time of construction. However, you can use keyword arguments to specify some default headers.
- キーワード引数を使用してリクエストで送信するヘッダを指定する、とありますね。なるほど。
headers
を使うことで、実質的に辞書を解凍し、各キーと値のペアを別々のキーワード引数としてpost()
メソッドに渡していることになるんですね。 - Djangoの
self.client.post()
メソッドでは、メソッドのシグネチャは次のようになります。**extra
パラメータは、リクエストのHTTPヘッダとして扱われる追加のキーワード引数を渡すことができます。
def post(self, path, data=None, content_type='application/octet-stream', follow=False, secure=False, **extra):
- ということで、今回の大きな学びは以下の二つ。
-
self.client.post()
メソッドを使う場合、HTTP ヘッダは'HTTP_'
を先頭につけて大文字に変換する必要があること -
self.client.post()
メソッドを使ってリクエストを行う場合、ヘッダーは辞書としてではなく、キーワード引数として渡す必要があること。
-
- これで、
x-api-key
ヘッダーを指定する際に、キーワード引数のheaders
辞書のキーとしてHTTP_X_API_KEY
を使用することで無事にテストすることができました。
③そのほかのヘッダー部分の説明
-
self.client.post
を使用して/api/
へのPOSTリクエストをシミュレートします。 -
follow=True
:リダイレクトを追跡する設定になります。 -
content_type='application/json'
:リクエストのコンテンツタイプはJSONを指定していることを示しています。-
content_type
を指定しない場合、データはmultipart/form-data
のコンテンツタイプで送信されます。
-
-
accept='application/json'
:JSON形式のレスポンスを返すことを期待していることを示しています。 - 他にも、
secure=True
にすると、HTTPSリクエストをエミュレートしたりできます。 - 今回は
self.client.post()
メソッドを使用してPOSTリクエストを送信していますが、他のHTTPメソッド(GET、PUT、DELETEなど)も同様に使用することができます。必要に応じて、適切なメソッドを選択してテストケースを作成しましょう。この辺は上述の公式ドキュメントにも詳細に記載があります。
リクエストボディとアサーションについて
- リクエストボディについては
data = {'key': 'value'}
が該当します。データとしてdata
変数に{'key': 'value'}
という辞書が定義されています。実際は、data
変数に適切なデータを設定し、期待される振る舞いをテストすることになります。 - テストケース内の
response
オブジェクトには、APIからのレスポンスに関する情報が含まれています。 - Pythonではアサーションを使用して、レスポンスのステータスコードが
200
であることをテストできます。それが以下のコードです。
self.assertEqual(response.status_code, 200)
- 一つ目では
SAMPLE_API_KEY
という正しいAPIキーが入っているのでステータスコード200
でテストに成功します。 - 二つ目では、
WRONG_API_KEY
という間違ったAPIキーが入っているので、ステータスコード401
でテストに成功します(任意のエラーステータスとエラーメッセージを返すようにしている場合は都度ここを変える必要あり)。