はじめに
JMeterで性能テストをしていて、ExcelファイルのアップロードだけどうしてもJMeterで再現できず、手動で計測していたことがありました。今回改めて性能テストを担当することになり、試行錯誤した結果JMeterで自動化できたので、その方法をまとめます。
何が難しいのか
ブラウザの操作だと「ファイルを選んで送信ボタンを押す」だけですが、これをJMeterで再現しようとすると意外とハードルがあります。
| ハードル | 内容 |
|---|---|
| 認証 | OTP認証があるとJMeterだけではログインできない |
| ファイル送信 | 通常のPOSTとは違い multipart/form-data で送る必要がある |
| パラメータ引き継ぎ | 画面遷移が複数ステップある場合、前の画面の値を次に渡す必要がある |
| 並列実行 | スレッドごとに異なるファイルを送りたい |
以降、それぞれどう解決したかを紹介します。
1. OTP認証をどうするか
問題
OTP(ワンタイムパスワード)認証はJMeterで自動化できません。毎回違うコードが発行されるので、ログインのリクエストをそのまま再現しても通りません。
解決策
ブラウザで先にログインして、そのセッションIDをJMeterに使わせる方式にしました。
① ブラウザでログイン(OTP認証を通す) ② 開発者ツール(F12) → Application → Cookies → JSESSIONIDの値をコピー ③ JMeterにその値を設定 ④ JMeterはログイン済みのセッションとしてリクエストを送信
JMeterの設定
ユーザー定義変数 にコピーした値を設定:
| 変数名 | 値 |
|---|---|
JSESSIONID |
ブラウザからコピーした値 |
HTTP Cookie Manager でリクエストに載せる:
| 項目 | 値 |
|---|---|
| 名前 | JSESSIONID |
| 値 | ${JSESSIONID} |
| ドメイン | 対象サーバーのホスト名 |
| Secure | true(HTTPS環境の場合) |
注意: セッションタイムアウトがあるので、取得後は速やかにテストを実行すること。
2. Excelファイルのアップロード
問題
ブラウザでファイルをアップロードするとき、裏では multipart/form-data という特殊な形式でファイルデータを送信しています。JMeterの通常のPOSTリクエストではこの形式にならないので、そのままではサーバーがファイルを受け取れません。
解決策
HTTPリクエストの設定で2つのことをします。

やること1: multipart/form-data を有効にする
HTTPリクエストの画面にある 「Use multipart/form-data」チェックボックスをON にします。これだけで、JMeterがファイル添付モードでリクエストを送るようになります。
やること2: アップロードするファイルを指定する
HTTPリクエストの 「Files Upload」タブ で、以下の3つを設定します。
| 項目 | 設定値 | 説明 |
|---|---|---|
| ファイルパス | ${excel_file_path} |
アップロードするファイルの場所 |
| パラメータ名 | uploadFile |
サーバー側が受け取るパラメータ名(HTMLの のname属性に合わせる) |
| MIMEタイプ | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
.xlsx のMIMEタイプ(.xls なら application/vnd.ms-excel) |
ファイルと一緒にhidden項目などの通常パラメータも送りたい場合は、「パラメータ」タブに追加すればOKです。
3. 画面遷移のパラメータ引き継ぎ
問題
アップロード処理が1回のリクエストで完結せず、複数ステップに分かれていることがあります。
Step1: ファイル送信 → 確認画面が返ってくる Step2: 確認画面で確定 → 登録処理 Step3: 登録確定 → 完了
この場合、Step1のレスポンスHTML内にあるhidden項目の値(例: ファイルの一時保存キー等)をStep2のリクエストに含める必要があります。ブラウザなら自動で送られますが、JMeterでは自分で抽出して渡す必要があります。
解決策: 正規表現抽出
Step1のHTTPリクエストの子要素として正規表現抽出を追加し、レスポンスHTMLから値を取り出します。
例えば、レスポンスに以下がある場合
<input name="s3Key" type="hidden" value="abc123" />
| 項目 | 設定値 |
|---|---|
| 参照名 | s3Key |
| 正規表現 | name="s3Key"[^>]*value="([^"]*)" |
| テンプレート | $1$ |
| 一致番号 | 1 |
これで上記の例だと value="abc123" の abc123 部分が抽出され、後続のリクエストで ${s3Key} として参照できるようになります。

件数が可変の配列パラメータの場合
hidden項目が sheetNames[0], sheetNames[1], … のように件数が決まっていない配列の場合は、正規表現抽出だけでは対応できません。BeanShell PreProcessorを使って動的にパラメータを組み立てます。
BeanShell PreProcessorとは?
HTTPリクエストを送る直前にJavaコードを実行できるJMeterの機能です。通常の設定画面だけでは対応できない処理(パラメータの動的な組み立て、条件分岐など)が必要なときに使います。
ステップ1: 正規表現抽出で全件取得する
| 項目 | 設定値 |
|---|---|
| 参照名 | sheetName |
| 正規表現 | name="sheetNames\[\d+\]"\s+value="([^"]*)" |
| 一致番号 | -1(全件抽出。デフォルトの1だと1件しか取れない) |
-1 を指定すると、sheetName_1, sheetName_2, … と sheetName_matchNr(件数)が変数にセットされます。
ステップ2: BeanShell PreProcessorでリクエストパラメータに追加する
JMeterの画面左側のツリーで、対象のHTTPリクエストを右クリック →「追加」→「前処理」→「BeanShell PreProcessor」を選択します。追加すると右側にテキストエリア(Script欄)が表示されるので、そこに以下のJavaコードを書きます。

やっていることは「正規表現抽出で取り出したシート名を、次のリクエストのパラメータとして追加する」です。
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
// 正規表現抽出で取得したシート名の件数を取得
String countStr = vars.get("sheetNames_count");
if (countStr != null) {
int count = Integer.parseInt(countStr);
// これから送るHTTPリクエストのパラメータを取得
org.apache.jmeter.config.Arguments args = sampler.getArguments();
// 抽出した値を1件ずつリクエストパラメータに追加
for (int i = 0; i < count; i++) {
String val = vars.get("sheetNames_" + i);
if (val != null) {
HTTPArgument arg = new HTTPArgument(
"sheetNames[" + i + "]", val);
arg.setAlwaysEncoded(true);
args.addArgument(arg);
}
}
}
これでリクエストに sheetNames[0]=Sheet1&sheetNames[1]=Sheet2&... が動的に追加されます。
4. 並列実行時のファイル割り当て
問題
並列度5でテストしたいとき、5スレッド全部が同じファイルを送ると実態に即しません。スレッドごとに異なるファイルを送りたい。
解決策
CSV Data Set Config でスレッドごとにファイルパスを割り当てます。
まずCSVファイルを用意:
excel_file_path /path/to/upload_1.xlsx /path/to/upload_2.xlsx /path/to/upload_3.xlsx /path/to/upload_4.xlsx /path/to/upload_5.xlsx
CSV Data Set Configの設定:

| 項目 | 設定値 |
|---|---|
| ファイル名 | CSVファイルのパス |
| 変数名 | excel_file_path |
| 最初の行を無視 | true |
| リサイクル | false |
| 共有モード | 全スレッド |
あとはHTTPリクエストのファイルパスに ${excel_file_path} を指定するだけです。スレッド1→1行目、スレッド2→2行目…と自動的に割り当てられます。
テストプラン全体の構成
最終的なテストプランの構成です。
テストプラン ├── ユーザー定義変数(ホスト名, JSESSIONID 等) ├── スレッドグループ(並列度5、ループ1回) │ ├── CSV Data Set Config(ファイル割り当て) │ ├── HTTP Cookie Manager(JSESSIONID) │ ├── HTTP共通設定(ホスト、ポート、プロトコル) │ │ │ ├── Step1【HTTPリクエスト】 │ │ ├── multipart/form-data + ファイルアップロード │ │ └── 正規表現抽出(hidden項目を抽出) │ │ │ ├── Step2【HTTPリクエスト】 │ │ ├── BeanShell PreProcessor(配列パラメータ組み立て) │ │ └── 正規表現抽出(次ステップ用) │ │ │ ├── Step3【HTTPリクエスト】 │ │ │ └── リスナー(結果ツリー、統計レポート)
ハマったポイント
multipart/form-data のチェック忘れ
ファイルアップロードの設定をしても、「multipart/form-dataを使用」にチェックが入っていないとただのPOSTになります。見た目は地味なチェックボックスなので見落としやすいです。
MIMEタイプの指定漏れ
MIMEタイプを空にするとサーバー側でファイルとして認識されないことがあります。.xlsx は長いですが正確な指定が必要です。
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
正規表現抽出の一致番号 -1
配列パラメータを全件抽出するには一致番号を -1 にします。デフォルトの 1 だと1件しか取れません。
BeanShellのインデックスのズレ
正規表現抽出の変数は sheetName_1 から始まる(1始まり)のに対し、サーバーに送るパラメータはsheetNames[0]から始まる(0始まり)です。変換を忘れるとサーバー側でパラメータが受け取れません。
まとめ
- OTP認証がある環境でも、ブラウザからJSESSIONIDを取得してCookie Managerに注入すればテスト可能
- Excelアップロードは
multipart/form-dataチェックON + MIMEタイプの正確な指定がポイント - 複数ステップの画面遷移は正規表現抽出でパラメータを引き継ぐ
- 可変の配列パラメータはBeanShell PreProcessorで動的に組み立てる
- 並列テストはCSV Data Set Configでスレッドごとにファイルを割り当て
「JMeterでファイルアップロードはできない」と思っていましたが、やってみたら設定の組み合わせで実現できました。同じような状況で困っている方の参考になれば幸いです。