JSON解析によるAPIテストという選択肢

3 min read読了の目安(約2800字

JSON解析によるAPIテストという選択肢

はじめに

APIテストを実施する上で、代表的であろうdreddなどのツールを検討してみましたが、LaravelなどのWebフレームワークから呼び出しづらい、APIの通信にセッションを利用しているとテストが難しい、日本語やExampleの資料が少ないなどの困難がありました。

そこで今回は上記の問題を解消するJSON解析によるAPIテストの詳細を備忘録として記載していきたいと思います。

TL;DR

テストツールからAPIリクエスト、レスポンスなどをJSONファイルに吐いて、openapi4j, swagger-parser, json-schemaなどのライブラリを用いることで、OpenAPIと実装したAPIが乖離がないことを検証出来る

JSON解析によるAPIテスト

JSON解析によるAPIテストではAPIサーバーやAPIテストツールの言語やAPIとの通信手段にセッションを利用しているかどうかなどは問題にはなりません。

必要な手順は以下の2点です。

  1. APIのテスト時にAPIのパスやリクエスト、レスポンスをJSONに出力する
  2. 出力したJSONをバリデーションツールに渡して検証する

まずは泥臭いですが、テストツールからAPIの情報をファイルに出力します、自分でヘルパーを用意するか、HTTP通信を傍聴するかなどの手段を用います。

大抵のテストツールにはbeforeEachafterAllなどのライクサイクルが提供されていますので、それらにフックさせるのがベターかなと思います。

次に出力したJSONをバリデーションツールに渡して検証します。

以下ではswagger-parserjson-schemaを例にバリデーションを行うサンプルを記載したいと思います。

api.yml

openapi: 3.0.0
info:
  title: api
  version: '1'
paths:
  /person:
    post:
      summary: Create new person
      responses:
        '200':
          description: OK
      operationId: post-person
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
              required:
                - name
    parameters: []

data.json

検証対象となるデータです。

{
    "name": "foo"
}

ValidationSample.java

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.SwaggerParseResult;

import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;

import org.json.JSONObject;

import java.nio.file.Files;
import java.nio.file.Path;

class ValidationSample {
    public void execute() throws Throwable {
      // OpenAPIを読み取る
      OpenAPI openAPI = new OpenAPIV3Parser().readLocation("/api.yml", null, null).getOpenAPI();

      // APIテストの際に出力されたJSONデータを読み取る
      String data = String.join("", Files.readAllLines(Path.of("/data.json")));

      var requestSchema = openAPI.getPaths().get("/person").getPost().getRequestBody().getContent().get("application/json").getSchema();

      // スキーマをバリデーションライブラリのモデルにラップする
      Schema validator = SchemaLoader.load(new JSONObject(requestSchema));

      validator.validate(new JSONObject(data));
    }
}

上記のサンプルコードに関してgradleやDockerfileなどの設定ファイルは下記のリポジトリにて公開しています。

https://github.com/piteroni/api-specification

最後に

Java、Rubyなどに比べライブラリに貧しいPHPでどうにかOpenAPIによるテストを実現できないか?というのが本記事の背景でした。

しかし、やはり本来的にはcommitteeのように、assert_response_schemaなるアサーションによるテストを記述するべきだと思います…。