Azure Load Testing が複数のスクリプトをサポートしたので JMeter の Include Controller を試してみた

Azure Load Testing が複数のスクリプトをサポートしたので JMeter の Include Controller を試してみた

Clock Icon2025.02.24

いわさです。

先日のアップデートで Azure Load Testing が複数スクリプトをサポートするようになりました。

https://azure.microsoft.com/en-us/updates?id=480463

以前まではひとつのテスト計画でアップロードできる JMeter スクリプトはひとつまでだった(データファイルや構成ファイルを併せてアップロードすることはできた)のですが、今回のアップデートで複数のテストスクリプトに対応しました。

テストシナリオの設計でテストモジュールの分割を行いたい場合などにも対応できるようになります。
JMeter スクリプトを複数ファイルに分割管理する方法を私はあまり使ったことがなかったのですが、良い機会と思い JMeter スクリプトで複数スクリプト化を行って動作させてみました。

1 つの JMeter スクリプトファイル上に複数のスレッドグループ

まずは次のようなひとつのテストプラン内に複数のスレッドグループがあって、それぞれで HTTP リクエストサンプラーを実行するような単純なケースを作成します。これは分割前のものです。

Cursor_and_MultiThreadGroup_jmx___Users_iwasa_takahito_work_hoge0224locust_MultiThreadGroup_jmx__-_Apache_JMeter__5_6_3_.png

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan">
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test Plan1">
        <intProp name="ThreadGroup.num_threads">1</intProp>
        <intProp name="ThreadGroup.ramp_time">1</intProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller">
          <stringProp name="LoopController.loops">1</stringProp>
          <boolProp name="LoopController.continue_forever">false</boolProp>
        </elementProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request">
          <stringProp name="HTTPSampler.domain">site1.example.com</stringProp>
          <stringProp name="HTTPSampler.protocol">https</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test Plan2">
        <intProp name="ThreadGroup.num_threads">1</intProp>
        <intProp name="ThreadGroup.ramp_time">1</intProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller">
          <stringProp name="LoopController.loops">1</stringProp>
          <boolProp name="LoopController.continue_forever">false</boolProp>
        </elementProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request">
          <stringProp name="HTTPSampler.domain">site2.example.com</stringProp>
          <stringProp name="HTTPSampler.protocol">https</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

このスクリプトを Azure Load Testing のテスト計画作成からアップロードします。

Cursor_and_テストの編集_-_Microsoft_Azure.png

なお、以前は非圧縮のファイルは最大 1,000 個まで、Zip 圧縮は 5 個までだったのですが、非圧縮ファイルが 10,000 個、Zip 圧縮が 100 個までと枠が増えていました。いつのまに...。

アップロード後にテスト実行したところ、2 回のリクエストが実行されました。

4FEA1508-38CC-4A29-9082-3EBA28421F06.png

複数モジュールに分割する

さてこれを複数のスクリプトに分割します。
どうやら JMeter では Include Controller を使うことで外部スクリプトファイルをインクルードさせることができるみたいです。

https://jmeter.apache.org/usermanual/component_reference.html#Include_Controller

ポイントとしては外部モジュールはテストプラン内にテストフラグメントを作成し、その中にサンプラーなどを追加して作成する必要があります。
単体でデバッグするためにスレッドグループを追加することもできるそうですが、インクルードされる時に無視されるとのこと。

ということで外部 JMeter スクリプトとして次のようにテストフラグメントを作成し、その中に HTTP リクエストサンプラーを配置しました。

0F7A1021-4451-46EA-AA9B-B0341F61C7F3_4_5005_c.jpeg

で呼び出し側のスクリプトファイル上では次のように Include Controller を使って参照します。

24477345-4C18-473F-A2E4-28CE542B3757_4_5005_c.jpeg

作成したスクリプトは次のような感じです。こちらがメインスクリプト。

hogemain.jmx
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan">
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group">
        <intProp name="ThreadGroup.num_threads">1</intProp>
        <intProp name="ThreadGroup.ramp_time">1</intProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller">
          <stringProp name="LoopController.loops">1</stringProp>
          <boolProp name="LoopController.continue_forever">false</boolProp>
        </elementProp>
      </ThreadGroup>
      <hashTree>
        <IncludeController guiclass="IncludeControllerGui" testclass="IncludeController" testname="Include Controller">
          <stringProp name="IncludeController.includepath">frag1.jmx</stringProp>
        </IncludeController>
        <hashTree/>
        <IncludeController guiclass="IncludeControllerGui" testclass="IncludeController" testname="Include Controller">
          <stringProp name="IncludeController.includepath">frag2.jmx</stringProp>
        </IncludeController>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

こちらがテストフラグメントです。

frag1.jmx
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan">
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
    </TestPlan>
    <hashTree>
      <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Test Fragment" enabled="false"/>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request">
          <stringProp name="HTTPSampler.domain">site1.example.com</stringProp>
          <stringProp name="HTTPSampler.protocol">https</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

でこれらをアップロードしましょう。
その上で、「ファイルの関連性」にてメインテストスクリプトを指定します。ここで指定されたスクリプトが、負荷テスト実行時のエントリポイントとなります。

5FEDDB32-7C16-4177-AC3E-068DBA60A7F9.png

実行してみたところ無事に分割されたモジュールがそれぞれ実行されていることが確認できました。

Cursor_and_TestRun_2_24_2025_6_49_31_AM_-_Microsoft_Azure.png

さいごに

本日は Azure Load Testing が複数のスクリプトをサポートしたので JMeter の Include Controller を試してみました。

Include Controller 使うの初めてだったのですが、シナリオ形式で複数のテストを用意する際に再利用性が高まって良さそうですね。毎回同じサンプラー作成しちゃってました。

ただ、JMeter のベストプラクティス「リソース使用量の削減」によると同じようなサンプラーを使う場合は Include Controller ではなくループで同じサンプラーを使用することが推奨されています。[1]

今回 Azure Load Tesitng で使えるようにはなりましたが、適切なケースで使用することを忘れないようにしたいです。

脚注
  1. ベストプラクティス_Apache JMeter ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.