pytest-httpserverを使ってhttp clientのテストを書く
pytestでhttp clientのテストを実装する際に、
pytest-httpserverというライブラリが便利だったので、
使い方のメモを残しておきます。
pytest-httpserver | GitHub
https://github.com/csernazs/pytest-httpserver
このライブラリを使うと、pytestのfixtureとして、
テスト用のhttp serverを実行する事ができます。
httpを利用して他システムと連携する機能などをテストする場合に便利です。
このエントリでは、いくつかのテスト例を示しますので、
公式のサンプルをあわせて参考にして頂ければと思います。
Howto | pytest_httpserver docs
https://pytest-httpserver.readthedocs.io/en/latest/howto.html
単純なテスト
次のコードが、ドキュメントの冒頭に記載されているサンプルです(少し変更してます)。
test_basic.py
import requests
from pytest_httpserver.httpserver import HTTPServer
def test_json_client(httpserver: HTTPServer):
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})
assert requests.get(httpserver.url_for("/foobar")).json() == {"foo": "bar"}
次のように依存ライブラリをインストールして実行します。
pip install pytest-httpserver
pip install requests
python -m pytest test_basic.py
簡単に説明すると、
test_json_client
メソッドの引数httpserver
がhttp serverのfixtureで、
次のコードで、予測されるHTTPのリクエスト・レスポンスを設定
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})
次のコードで、HTTPのリクエストを実行
assert requests.get(httpserver.url_for("/foobar")).json() == {"foo": "bar"}
という流れになります。
ファイルを返却するテスト
httpserverからファイルを返却したい場合は、
次のように、ファイルをreadしてresponse_dataに設定することで実現できます。
test_file.py
import requests
from pytest_httpserver.httpserver import HTTPServer
def test_response_file(httpserver: HTTPServer):
body = open("./sample.png", "rb").read()
httpserver.expect_request("/foobar").respond_with_data(
content_type="image/png",
response_data=body,
)
resp = requests.get(httpserver.url_for("/foobar"))
assert int(resp.headers["Content-Length"]) == len(body)
assert resp.content == body
リクエストが呼ばれたかどうかのテスト
呼び出したリクエスト・返却したレスポンスは、httpserver.log
に記録されているので、
この内容をチェックすればチェックができます。
ここではPyHamcrestを使った実装の例を示します。
# unittest.mock
のassert_has_calls
みたいなものがあればよいのですが、
PyHamcrest
https://github.com/hamcrest/PyHamcrest
test_assert_request.py
import requests
from hamcrest import assert_that, has_item, has_entries
from pytest_httpserver.httpserver import HTTPServer
def test_assert_request(httpserver: HTTPServer):
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})
assert requests.get(httpserver.url_for("/foobar?x=1")).json() == {"foo": "bar"}
assert_that(
[{"_path":req.path, **dict(req.args)} for (req, res) in httpserver.log],
has_item(has_entries({"x": "1", "_path": "/foobar"}))
)
PyHamcrestは、次のようにインストールします。
pip install PyHamcrest
HTTPS(SSL)のリクエストのテスト
HTTPS(SSL)のテスト方法は、次のドキュメントに書かれています。
Running an HTTPS server | pytest_httpserver docs
https://pytest-httpserver.readthedocs.io/en/latest/howto.html#running-an-https-server
ここでは、上記のリンクとは少し変更して、
環境変数REQUESTS_CA_BUNDLE
に証明書を設定する例を示します。
test_https.py
import pytest
import trustme
import requests
import os
import ssl
from pytest_httpserver.httpserver import HTTPServer
@pytest.fixture(scope="session")
def ca():
return trustme.CA()
@pytest.fixture(scope="session")
def httpserver_ssl_context(ca):
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_cert = ca.issue_cert("localhost")
localhost_cert.configure_cert(context)
return context
@pytest.fixture(scope="session")
def httpclient(ca):
with ca.cert_pem.tempfile() as ca_temp_path:
os.environ["REQUESTS_CA_BUNDLE"] = ca_temp_path
yield ca_temp_path
def test_requests(httpserver: HTTPServer, httpclient):
httpserver.expect_request("/").respond_with_data("hello world!")
result = requests.get(httpserver.url_for("/"))
assert result.text == "hello world!"
trustmeは、次のようにインストールします。
pip install trustme
以上。