Quantcast
Channel: Postmanタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 470

OpenAPIドキュメントから全APIの自動テストを生成する

$
0
0

はじめに

グロースエクスパートナーズ Advent Calendar 2020 3日目。
yitoです。

API開発をしている中で、テストするのに毎回クライアントツールにリクエストを用意してAPIを呼び出すのが手間でした。
それを、コマンド一発で、API仕様書に定義した全てのAPIをテストできるようにしたので、その方法を紹介します。

概要

OpenAPIドキュメントをAPIクライアントツールで利用可能なJSONに変換し、それをCLIライブラリで実行します。
これを実現する、以下について順番に説明していきます。

  • Postmanについて
  • OpenAPI 3.0 to Postman Collection v2.1.0 Converter
  • Postman Collection SDK
  • newman

Postmanについて

APIリクエストのクライアントツールにPostmanがあります。
Postmanは、以下のようなことができます。

スクリーンショット 2020-11-26 0.00.35.png

書き出したリクエスト情報を保存すると、画面左側にあるPostman Collectionsに追加され、フォルダでの管理ができます。
このPostman Collectionsは、Webに公開する(制限をかけることも可能?)か、JSONでのexport/importで、開発チーム内で共有が可能です。

OpenAPI 3.0 to Postman Collection v2.1.0 Converter

OpenAPI 3.0 to Postman Collection v2.1.0 Converterは、OpenAPIドキュメントをPostman CollectionのJSONに変換する、NodeJSで実行可能なライブラリです。
使い方は簡単で、OpenAPIのyamlを読み込んで、このライブラリのクラスに渡して実行するだけです。

constfs=require('fs');constreadFileData=fs.readFileSync('OpenAPIドキュメントのファイルパス',{encoding:'UTF8'});constConverter=require('openapi-to-postmanv2');Converter.convert({type:'string',data:readFileData},{},(err,conversionResult)=>{if(!conversionResult.result){console.error('API定義をPostman Collectionに変換できませんでした',conversionResult.reason);return;}constconvertData=conversionResult.output[0].data;// Postman CollectionsのJSONファイルを生成するfs.writeFile('postman-collections.json',JSON.stringify(convertData,null,4),(err)=>{if(err)console.error(err)});});

この生成されたJSONファイルを読み込むと、Postmanにて利用ができます。

スクリーンショット 2020-11-26 0.43.57.png

ただ、このままだと、各APIのリクエストパラメータが <long><string>のようになっていて、このままだと呼び出したいAPIのパラメータとしては不適切なので、使う際は書き換えが必要です。

手で1つ1つ直すのは面倒なので、Postman Collection SDKを使います

Postman Collection SDK

Postman Collection SDKは、Postman Collectionの生成・更新のための、NodeJSで実行可能なSDKです。
OpenAPI 3.0 to Postman Collection v2.1.0 Converterにて生成したPostman CollectionのJSONを、このSDKを使って編集します。

Postman CollectionのJSONファイルを読み込み、SDKにてCollectionをnewすると、以下のようなクラスが生成されます。
クラスについての詳細

  • Collection
    • Postman Collectionの1つに相当
    • メンバーにItemGroupを持つ
  • ItemGroup
    • Postman Collectionの1フォルダに相当
    • メンバーにItemを持つ
  • Item
    • Postman Collectionの1つのAPIに相当
    • メンバーにRequestを持つ
  • Request
    • APIのURL、リクエストパラメータに関する値
    • メンバーにHeaderList, EventList, VariableListなどを持つ

<long><string>のような値を実際に使いたい値に変えるため、 Requestの値を書き換えます。
こちらにあるOpenAPIドキュメント(api-spec.yml)、Postman Collection SDKを使った実装(postman-test/index.js)を使いながら説明します。

先ほどの実装に以下を追加します。

...constconvertData=conversionResult.output[0].data;constcollection=newCollection(convertData);collection.items.all().forEach(item=>updateItem(item))// Postman CollectionsのJSONファイルを生成するfs.writeFile('postman-collections.json',JSON.stringify(collection,null,4),(err)=>{if(err)console.error(err)});...

collection.itemsItemGroupまたは Itemがあります。そこから、 Requestを取り出して、 <long><string>のような値を、使いたい値に書き換えます。

...const{v4:uuidv4}=require('uuid');constupdateRequestVariable=(request,key,value)=>{constfindVariable=request.url.variables.find(variable=>variable.key===key);if(findVariable){findVariable.update({key:key,value:value})}}constupdateRequestQuery=(request,key,value)=>{constfindQueryParam=request.url.query.find(queryParam=>queryParam.key===key);if(findQueryParam){findQueryParam.update({key:key,value:value})}}constupdateRequest=(request)=>{// Authorizationif(request.auth&&request.auth.type==='apikey'){request.auth.update({"key":"api_key","value":`api-key-${uuidv4()}`},'apikey')}// 書籍関連のAPIif(request.url.getPath().includes('books')){updateRequestVariable(request,'bookId','100000001');}// ユーザー関連のAPIif(request.url.getPath().includes('users')){updateRequestVariable(request,'username','user-XXXX');updateRequestQuery(request,'username','user-XXXX');updateRequestQuery(request,'password','pass-XXXX');}returnrequest;}constupdateItem=(item)=>{if(item.items){item.items.all().forEach(item=>updateItem(item));}else{item.request=updateRequest(item.request);}returnitem;}...

レスポンスに対するテストも実行したいので、 updateItemメソッドに以下のコードを追加します。

...constupdateItem=(item)=>{if(item.items){item.items.all().forEach(item=>updateItem(item));}else{// 追加item.events.add({listen:'test',script:{exec:"pm.test('response 200 test', () => {\n"+"    pm.response.to.have.status(200);\n"+"});"},type:'text/javascript'})...

これでリクエストパラメータの書き換えがされた状態で、Postman CollectionのJSONが生成されます。

毎回JSONをimportしてAPIを呼び出すのは面倒なので、CLIだけで実行できるように、newmanを使います.

newman

newmanは、CLIでPostman CollectionのJSONを読み込みAPIをリクエストする、NodeJSで実行可能なライブラリです。

先ほどのコードで生成したJSONを、newmanで実行するように変えます。

...constcollection=newCollection(convertData);collection.items.all().forEach(item=>updateItem(item))fs.writeFile('postman-collections.json',JSON.stringify(collection,null,4),(err)=>{if(err)console.error(err)});newman.run({collection:collection,reporters:'cli',environment:require('./local.postman_environment.json')},(err)=>{if(err)console.error(err);});...
  • newman.run()
    • collection: Postman CollectionのJSONを指定
    • reports: 実行結果の出力方法の指定。CLI、Junit、JSON等が可能
    • envioroment: Postmanには環境ごとの変数の指定があり、生成されたJSONには baseUrlの指定が必要なため、向き先を指定したJSONを用意して読み込む

実行すると以下のようになります。

% npm run start
>node index.js

newman

Book Management

❏ books
↳ 書籍更新API
  PUT http://localhost:8080/v1/books [200 OK, 123B, 235ms]
  ✓  response 200 test

↳ 書籍登録API
  POST http://localhost:8080/v1/books [200 OK, 123B, 19ms]
  ✓  response 200 test

↳ 書籍一覧取得API
  GET http://localhost:8080/v1/books [200 OK, 800B, 11ms]
  ✓  response 200 test

↳ タグ絞り込み検索API
  GET http://localhost:8080/v1/books/findByTags?tags=<string>&tags=<string> [200 OK, 800B, 14ms]
✓  response 200 test

❏ books / {book Id}
↳ 書籍詳細取得API
  GET http://localhost:8080/v1/books/100000001 [200 OK, 290B, 10ms]
  ✓  response 200 test

↳ 書籍削除API
  DELETE http://localhost:8080/v1/books/100000001 [200 OK, 123B, 7ms]
  ✓  response 200 test

❏ users
↳ ユーザー登録API
  POST http://localhost:8080/v1/users [200 OK, 123B, 8ms]
  ✓  response 200 test

↳ ユーザー一覧取得API
  GET http://localhost:8080/v1/users [200 OK, 123B, 6ms]
  ✓  response 200 test

↳ ログインAPI
  GET http://localhost:8080/v1/users/login?username=user-XXXX&password=pass-XXXX [200 OK, 123B, 8ms]
  ✓  response 200 test

↳ ログアウトAPI
  GET http://localhost:8080/v1/users/logout [200 OK, 123B, 6ms]
  ✓  response 200 test

❏ users / {username}
↳ ユーザー詳細取得APi
  GET http://localhost:8080/v1/users/user-XXXX [200 OK, 123B, 6ms]
  ✓  response 200 test

↳ ユーザー更新API
  PUT http://localhost:8080/v1/users/user-XXXX [200 OK, 123B, 5ms]
  ✓  response 200 test

↳ ユーザー削除API
  DELETE http://localhost:8080/v1/users/user-XXXX [200 OK, 123B, 7ms]
  ✓  response 200 test

→ タグ一覧取得API
  GET http://localhost:8080/v1/tags [200 OK, 123B, 6ms]
  ✓  response 200 test

┌─────────────────────────┬───────────────────┬──────────────────┐
│                         │          executed │           failed │
├─────────────────────────┼───────────────────┼──────────────────┤
│              iterations │                 1 │                0 │
├─────────────────────────┼───────────────────┼──────────────────┤
│                requests │                14 │                0 │
├─────────────────────────┼───────────────────┼──────────────────┤
│            test-scripts │                14 │                0 │
├─────────────────────────┼───────────────────┼──────────────────┤
│      prerequest-scripts │                 0 │                0 │
├─────────────────────────┼───────────────────┼──────────────────┤
│              assertions │                14 │                0 │
├─────────────────────────┴───────────────────┴──────────────────┤
│ total run duration: 654ms                                      │
├────────────────────────────────────────────────────────────────┤
│ total data received: 1.37KB (approx)                           │
├────────────────────────────────────────────────────────────────┤
│ average response time: 24ms [min: 5ms, max: 235ms, s.d.: 58ms] │
└────────────────────────────────────────────────────────────────┘

以上で、コマンド一発でAPI全てをテストできるようになりました。

参考

サンプルコード

https://github.com/yito0000/openapi-postman-test-example


Viewing all articles
Browse latest Browse all 470

Trending Articles