概要
- 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でテストに成功します(任意のエラーステータスとエラーメッセージを返すようにしている場合は都度ここを変える必要あり)。