APIテストとは?Python(pytest+requests)で始める自動化入門

📌 この記事はこんな方におすすめ

  • APIテストが何かを知りたいQAエンジニア・開発者の方
  • UIテストとAPIテストの違いを理解したい方
  • Pythonで自動テストを始めたいエンジニアの方
  • pytestとrequestsの使い方を基礎から学びたい方

この記事を読むとわかること

  • APIテストとUIテストの違いと使い分け
  • requestsライブラリでHTTPリクエストを送る方法
  • pytestでAPIテストを自動実行する基本パターン
  • HTMLレポートを自動生成してポートフォリオに活用する方法

👨‍💻 筆者について

QAエンジニアとして実務でPlaywright・Python・pytestを使ったAPIテスト自動化を担当。本記事で使用するコードはすべてGitHubで公開しており、実際に動作確認済みのコードをそのまま解説しています。

「APIテストって難しそう…」と思っていませんか?実は requestsとpytestの2つのライブラリを組み合わせるだけで、実務レベルのAPIテストが書けます。

この記事では、APIテストの基本概念から環境構築・実際のコードまでを丁寧に解説します。UIテストしか経験のない方でも、読み終わる頃には「APIテストも自分で書ける」という自信がつきます。


00. APIテストとは?

APIテストとは、アプリケーションの「裏側の仕組み(API)」が正しく動いているかを確認するテストです。

UIテストがブラウザを操作して画面ごと確認するのに対し、APIテストはブラウザを使わずにHTTPリクエストを直接送信してレスポンスを検証します。

UIテスト APIテスト
確認する対象 画面・見た目・操作感 データ・ロジック・セキュリティ
ブラウザ 必要 不要
実行速度 遅い🐢 爆速⚡
壊れやすさ UI変更で壊れやすい ロジックが変わらない限り安定

💡 ポイント:UIテストとAPIテストは「どちらが優れている」ではなく、それぞれ役割が違います。両方できると、QAエンジニアとしての価値が大きく上がります。


01. なぜAPIテストが重要なのか?

現代のWebアプリはほぼ全てフロントエンド(画面)とバックエンド(API)が分離した構造になっています。

APIが壊れると、どんなに画面が正しく表示されていてもデータが保存されない・ログインできない・決済が失敗するといった致命的な問題が起きます。

また、APIテストはUIテストの10〜100倍速く実行できるため、CI/CDパイプラインに組み込んで毎回のデプロイ前に自動確認するのが実務の定番です。

# APIテストのイメージ
# ブラウザなし!コードだけでサーバーと通信する

import requests

response = requests.get("https://jsonplaceholder.typicode.com/users/1")
print(response.status_code)  # 200
print(response.json())       # {"id": 1, "name": "Leanne Graham", ...}

💡 ポイント:たった3行でAPIにリクエストを送り、レスポンスを確認できます。これがAPIテストの基本形です。


02. 環境構築

必要なライブラリのインストール

以下の3つをインストールするだけで動作します。

pip install requests pytest pytest-html
ライブラリ 役割
requests APIにHTTPリクエストを送る
pytest テストを実行・管理する
pytest-html HTMLレポートを自動生成する

pytest.ini の設定

プロジェクトのルートに pytest.ini を置くことで、テスト実行のたびにHTMLレポートが自動生成されます。

# pytest.ini
[pytest]
addopts = --html=report.html --self-contained-html

💡 Tip:一度設定すれば、以降は pytest test_api.py -v だけで自動的にHTMLレポートが生成されます。ポートフォリオのエビデンスとしても活用できます。


03. requestsライブラリの基本

HTTPメソッドの使い方

HTTPメソッドに対応したメソッドがそれぞれ用意されています。

import requests

# GET:データを取得する
response = requests.get("https://jsonplaceholder.typicode.com/users/1")

# POST:データを作成する
response = requests.post(
    "https://jsonplaceholder.typicode.com/users",
    json={"name": "Taro", "email": "taro@example.com"}
)

# PUT:データを更新する
response = requests.put(
    "https://jsonplaceholder.typicode.com/users/1",
    json={"name": "Updated Taro"}
)

# DELETE:データを削除する
response = requests.delete("https://jsonplaceholder.typicode.com/users/1")

レスポンスの確認方法

response = requests.get("https://jsonplaceholder.typicode.com/users/1")

print(response.status_code)  # ステータスコード: 200
print(response.json())       # レスポンスボディ(JSON形式)
print(response.headers)      # レスポンスヘッダー

💡 ポイント:response.json() を使うとレスポンスのJSONをPythonの辞書型として扱えます。そのままアサーションに使えるのが便利です。


04. pytestの基本

テストの書き方

関数名を test_ で始めるだけで、pytestが自動的にテストとして認識します。

import requests

def test_get_user():
    """ユーザー情報が正しく取得できること"""
    response = requests.get("https://jsonplaceholder.typicode.com/users/1")

    assert response.status_code == 200, f"期待値: 200, 実際: {response.status_code}"
    assert response.json()["id"] == 1
    assert "name" in response.json()

実行コマンド

# 全テストを実行
pytest

# 詳細表示で実行
pytest -v

# 特定のファイルだけ実行
pytest test_api.py -v

実行結果サンプル

test_api.py::test_get_user       PASSED  [ 33%]
test_api.py::test_create_user    PASSED  [ 66%]
test_api.py::test_delete_user    PASSED  [100%]

3 passed in 1.23s ✅

💡 ポイント:assert が失敗したときは、どの値が期待値と違ったかを自動で表示してくれます。デバッグがとても楽になります。


05. pytest + requests を組み合わせる

この2つを組み合わせると、実務レベルのAPIテストが書けます。JSONPlaceholderという無料のモックAPIを使って実際に動かしてみましょう。

import requests
import pytest

BASE_URL = "https://jsonplaceholder.typicode.com"

def test_get_all_users():
    """全ユーザーが取得できること"""
    response = requests.get(f"{BASE_URL}/users")

    assert response.status_code == 200
    assert len(response.json()) == 10  # 10件のユーザーが返ること

def test_create_user():
    """ユーザーが作成できること"""
    new_user = {"name": "Yoshitsugu", "email": "test@example.com"}
    response = requests.post(f"{BASE_URL}/users", json=new_user)

    assert response.status_code == 201
    assert response.json()["name"] == "Yoshitsugu"

def test_delete_user():
    """ユーザーが削除できること"""
    response = requests.delete(f"{BASE_URL}/users/1")

    assert response.status_code == 200

⚠️ 注意:JSONPlaceholderはモックAPIのため、実際にはデータが保存・削除されません。テスト学習用として安心して使えます。


06. ハマりポイント

実装中に実際につまずいた箇所をまとめました。同じところでハマる方の参考になれば嬉しいです。


① requestsとpytest-requestsを混同してしまう

最初に「pytestでHTTPリクエストを送るライブラリ」を検索したところ、pytest-requests というライブラリを見つけてインストールしてしまいました。実際に使うのは別々のライブラリで、requests(HTTPクライアント)と pytest(テストフレームワーク)を組み合わせて使います。

# ❌ pytest-requestsは今回使わない
pip install pytest-requests

# ✅ 正しいインストール
pip install requests pytest pytest-html

💡 ポイント:requests はHTTPリクエスト専用、pytest はテスト実行専用です。役割が違うので両方インストールして使います。


② response.json() でKeyErrorが出る

レスポンスのJSONから値を取り出そうとしたとき、存在しないキーを指定してしまい KeyError が発生しました。まずレスポンスの中身を確認してからアクセスする習慣が大切です。

# ❌ キーが存在しない場合にKeyErrorが発生
user_id = response.json()["userId"]  # KeyError!

# ✅ まずprint()で中身を確認する
print(response.json())
# {'id': 1, 'name': 'Leanne Graham', ...}

# ✅ get()を使うとKeyErrorを防げる
user_id = response.json().get("id")  # Noneが返るだけでエラーにならない

💡 ポイント:初めて触るAPIは必ず print(response.json()) でレスポンスの構造を確認してからアサーションを書きましょう。


③ assertが失敗してもエラーの原因がわからない

最初は assert response.status_code == 200 だけ書いていたため、失敗したときに「何が返ってきたか」がわからず原因調査に時間がかかりました。

# ❌ 失敗時に情報が少ない
assert response.status_code == 200

# ✅ エラーメッセージを追加して原因をすぐ把握
assert response.status_code == 200, f"期待値: 200, 実際の値: {response.status_code}"

💡 ポイント:assert 条件, "メッセージ" の形でメッセージを追加すると、失敗時に何が期待値で何が実際の値だったかがすぐわかります。


④ テストファイル名・関数名のルールを知らなかった

pytestがテストを自動認識しないケースが発生しました。原因はファイル名や関数名がpytestの命名規則に沿っていなかったことでした。

# ❌ pytestが認識しない
# ファイル名: api_test.py(test_で始まっていない)
def check_user():  # test_で始まっていない
    assert True

# ✅ pytestが自動認識する
# ファイル名: test_api.py(test_で始まる)
def test_check_user():  # test_で始まる
    assert True

⚠️ 注意:ファイル名は test_ で始めるか _test で終わる、関数名は test_ で始める、この2つがpytestの基本ルールです。


⑤ BASE_URLの末尾スラッシュでURLが二重になる

BASE_URLの末尾に / をつけた状態でパスを結合したところ、URLが //users のように二重スラッシュになってしまいリクエストが失敗しました。

# ❌ 二重スラッシュになってしまう
BASE_URL = "https://jsonplaceholder.typicode.com/"
response = requests.get(f"{BASE_URL}/users")
# → https://jsonplaceholder.typicode.com//users(NG)

# ✅ BASE_URLの末尾スラッシュを取り除く
BASE_URL = "https://jsonplaceholder.typicode.com"
response = requests.get(f"{BASE_URL}/users")
# → https://jsonplaceholder.typicode.com/users(OK)

💡 ポイント:BASE_URLの末尾には / をつけず、各パスの先頭に / をつける書き方に統一すると混乱しません。


07. よくある質問(FAQ)

Q. pytestでAPIテストをするメリットは?
A. Pythonで直感的にテストが書けて、CI/CDとの統合がしやすいのが最大のメリットです。また pytest-html でHTMLレポートを自動生成できるため、エビデンスの作成工数も大幅に削減できます。

Q. requestsとhttpxどちらが良い?
A. 用途によって使い分けるのがベストです。シンプルな同期処理なら requests、非同期処理(async/await)が必要なら httpx を選びましょう。APIテスト入門には requests の方がシンプルでおすすめです。

Q. UIテストとAPIテストはどちらから始めるべき?
A. APIテストから始めることをおすすめします。実行速度が速く、環境のセットアップもシンプルなため、テスト自動化の基礎を学ぶのに最適です。UIテストに慣れている方でも、APIテストを追加することで「両方できるエンジニア」としてのアピールになります。

Q. テスト対象のAPIがない場合はどうすればいい?
A. 練習用の公開APIを使いましょう。JSONPlaceholder(ユーザー・投稿のCRUD)や Restful Booker(認証フロー)がポートフォリオ用のAPIテストに最適です。どちらも無料で使えます。

Q. pytestのfixtureとは何ですか?
A. テストの前処理・後処理を共通化する仕組みです。例えば認証トークンの取得を fixture に書いておくと、複数のテストケースで使い回せます。テストコードの重複を減らし、メンテナンスしやすい構造にするための重要な機能です。


08. まとめ

この記事では、APIテストの基本概念とpytestとrequestsの使い方を解説しました。

ポイント 内容
APIテストとは ブラウザなしでHTTPリクエストを送ってレスポンスを検証するテスト
requestsの役割 APIへのHTTPリクエスト送信・レスポンス取得
pytestの役割 テストの実行・管理・HTMLレポート生成
組み合わせの強み シンプルなコードで実務レベルのAPIテストが実現できる

UIテストしか経験のない方でも、requestsとpytestの2つを覚えるだけでAPIテストを書けるようになります。GitHubにコードを公開することで「UIもAPIも両方できます!」というアピールになりますよ。次の記事では実際のAPIテストケースを詳しく解説します。

タイトルとURLをコピーしました