Help us understand the problem. What is going on with this article?

swaggerを用いて JMeter のテストシナリオを作成する

More than 1 year has passed since last update.

swagger を用いると、API の仕様をブラウザで確認できるだけでなく、様々なコードの自動生成を行うことにより開発効率を向上させることができます。

ここでは、swagger ファイルから JMeter のテストシナリオを自動生成して、負荷試験を行う環境を用意してみます。

swagger-codegen jmeter

overview

https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JMeterCodegen.java

swagger-codegen の jmeter 生成用の実装は上記になります。行うことは比較的シンプルで、以下の2ファイルの生成を行います。

  • xxx.jmx : テストシナリオファイル
  • xxx.csv : テストに使用するパラメータファイル

generate

swagger-codegen の実行は、以下のように行います。事前に swagger-codegen などのインストール・設定は済ませた上で実施してください。

java -jar swagger-codegen-cli.jar generate  \
  -i swagger.json  \
  -l jmeter \
  -o ./jmeter \

-o オプションで指定したディレクトリに、テストシナリオとCSVファイルが生成されます。

sample file

{
  "swagger": "2.0",
  "info": {
    "description": "Api Documentation",
    "version": "1.0.0",
    "title": "Api Documentation",
    "termsOfService": "urn:tos",
    "contact": {},
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0"
    }
  },
  "host": "localhost:8080",
  "basePath": "/",
  "tags": [
    {
      "name": "sada-controller",
      "description": "Sada Controller"
    }
  ],
  "paths": {
    "/sada": {
      "get": {
        "tags": [
          "sada-controller"
        ],
        "summary": "sada",
        "operationId": "sadaUsingGET",
        "consumes": [
          "application/json"
        ],
        "produces": [
          "*/*"
        ],
        "parameters": [
          {
            "name": "echo",
            "in": "query",
            "description": "echo",
            "required": false,
            "type": "string",
            "default": "masashi"
          }
        ],
        "responses": {
          "200": {
            "description": "echo",
            "schema": {
              "type": "string"
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    }
  }
}

上のサンプル JSON を用いて、実際に swagger-codegen 実行してみます。実行すると以下のファイル群が生成されます。

  • .swagger-codegen/
  • .swagger-codegen-ignore
  • SadacontrollerApi.csv
  • SadacontrollerApi.jmx

jmx

テストシナリオの雛形です。

接続先のサーバー(host: localhost) や port 番号(port: 8080)は仮のものになっているので、必要に応じてファイルを修正するか、実行時にパラメータとして渡して指定します。

負荷試験時に使用するパラメータは、後述の CSV ファイルを読み込んで指定するようになっています。こちらも手直しが必要であれば手直しをします。

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="SadacontrollerApi Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments">
          <elementProp name="host" elementType="Argument">
            <stringProp name="Argument.name">host</stringProp>
            <stringProp name="Argument.value">localhost</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="port" elementType="Argument">
            <stringProp name="Argument.name">port</stringProp>
            <stringProp name="Argument.value">8080</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
        </collectionProp>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments">
          <elementProp name="testCases" elementType="Argument">
            <stringProp name="Argument.name">testCases</stringProp>
            <stringProp name="Argument.value">${__P(testCases,10)}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
(snip.)

csv

テストデータのCSVファイルです。

渡すべき項目についてはある程度網羅されていますが、実際に渡すパラメータはかなり適当なものが含まれているので、こちらについては手で望ましいものに修正します。

testCase,httpStatusCode,echo
Success,200,0

JMeter

JMeter install

テストシナリオの手直しを終えたら、実際に Jmeter を動かしてみます。

JMeter のインストールは、Ubuntu 環境であれば apt-get 、 Mac であれば brew コマンドで行えます。

# ubuntu
$ sudo apt-get install -y jmeter
# mac
$ brew install jmeter

JMeter run

コマンドラインでは、以下のようなコマンドで実行します。

jmeter -n -t (jmx file) \
             -l sada.jtl \
             -e -o report \
             -Jhost=1.2.3.4 \
             -Jport=80
  • -n : コマンドラインモード(Non GUI モード)で起動
  • -t : テストシナリオファイル(jmx) を指定
  • -l : テストの実行結果を出力するファイル(jtl) を指定
  • -e : HTML レポートを出力
  • -o : レポートファイルの出力先ディレクトリを指定
  • -Jxxx : jmx ファイル中に記載されている Property の設定・上書きを行う。 -Jhost であれば host という property の値を渡した値で上書きする。

以下は実行例です。

$ jmeter -n -t ./bin/jmeter/SadacontrollerApi.jmx -l sada.jtl -e -o report -Jhost=x.x.x.x -Jport=80
Creating summariser <summary>
Created the tree successfully using ./bin/jmeter/SadacontrollerApi.jmx
Starting the test @ Mon Apr 09 12:12:00 JST 2018 (1523243520009)
Waiting for possible Shutdown/StopTestNow/Heapdump message on port 4445
summary +      1 in 00:00:01 =    1.9/s Avg:   103 Min:   103 Max:   103 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +      9 in 00:00:00 =   85.7/s Avg:    10 Min:     8 Max:    15 Err:     0 (0.00%) Active: 0 Started: 1 Finished: 1
summary =     10 in 00:00:01 =   15.6/s Avg:    19 Min:     8 Max:   103 Err:     0 (0.00%)
Tidying up ...    @ Mon Apr 09 12:12:01 JST 2018 (1523243521083)
... end of run

JMeter result

上述のコマンドで実行した場合、結果は以下2種類のファイルで出力されます。

  • jtl ファイル
  • HTML レポート

jtl ファイル

JMeter によるテストの実行ログが出力されます。

timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,Latency,IdleTime,Connect
1523242680196,97,sadaUsingGET - Success,200,,Thread Group - sadaUsingGET 1-1,text,true,,197,127,1,1,96,0,65
1523242680300,9,sadaUsingGET - Success,200,,Thread Group - sadaUsingGET 1-1,text,true,,197,127,1,1,9,0,0
(snip.)

これで各シナリオでどのような動きになったか詳細が終えますが、よりサマライズされた結果を見たい場合は HTML レポートを見ます。

HTML レポート

-o オプションで指定したディレクトリに HTML ファイルが出力されます。こちらをブラウザで開くと、Jmeter の実行結果をグラフ等々でよりわかりやすくビジュアライズすることができます。

image.png
image.png
image.png

課題

swagger-codegen による JMeter のテストシナリオ自動生成は、ある程度の雛形までは自動的に作ってくれますが、実行時に用いるパラメータなど、自動生成されたものから色々とチューニングを行う必要があります。

とはいえ、どうしてもテスト設計者の思いつきでシナリオが作られやすく、かつメンテナンスがされず使い捨て的にテストが管理されることが多いのが負荷テストを取り巻く現状かなと認識しています。

このように Swagger を起点としてこのようなプロセスである程度のところまで自動生成する方が、より手間も少なくなりますし、人間が本来しなくても良い作業が不要になりますし、属人性が排除できると思います。

まとめにかえて

Swagger で API 仕様を表現する、という開発規約をきちんと用意することで、API 仕様を明示化するという効能以上に、様々な開発効率を向上させる施策を開発プロジェクトにもたらすことが可能になります。

その一例として、Swagger を用いて JMeter のテストシナリオを作成してみました。
他にも用途が多いので、API の仕様は Swagger (Open API) で管理していきたいですね。

moaikids
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした