はじめに
負荷テスト本番ではレスポンスデータを保存することはないだろうが、テストプランの検証のためレスポンスデータを出力、保存したいケースはあると思う
※ファイルダウンロード機能の検証のイメージ
ということで、その方法について調査してみた
対象バージョン
- Apache JMeter : 5.2.1
想定シナリオ
- 適当なサンプルページを用意してアクセス
- ファイルをダウンロードする
こういったサンプルファイルを用意
これをJMeterからのテスト実施時に保存したいものとする
基本的なテストシナリオは「HTTP(S) Test Script Recorder」を使って作成済のこととする
「Save Responses to a file」を使う
まずはListenerである「Save Responses to a file」を試してみる
- 対象のSamplerに対して「Save Responses to a file」を追加
- 実行~結果確認
シナリオは成功
結果、bin配下にファイルは出力されたが標準では連番+content-typeで微妙なファイル名に
- 「Save Responses to a file」の属性について
ファイル名関連では以下のような属性が用意されており、Filename prefixを使用すればファイル名の固定は可能だが変数は使えないとのこと、複数スレッドで実行した場合などは確認しずらい、あるいはできない
属性 | 説明 |
---|---|
Filename Prefix (can include folders) | ファイル名の接頭辞、ほかの接尾辞、接頭辞を無効にすれば固定のファイル名は可能。変数は使用不可 |
Variable Name containing saved file name | 生成されたファイル名を格納する変数、後続の処理で利用可能(この変数の値をファイル名に使う、ということではない) |
Minimum Length of sequence number | 接頭辞の連番の最低桁数(デフォルトは0) |
Don't add number to prefix | 接頭辞に連番を付与しない |
Don't add content type suffix | 接尾辞にcontent typeを追加しない |
Add timestamp | 接尾辞に「yyyyMMdd-HHmm_」フォーマットの日付を追加 |
「JSR223 PostProcessor」を使う
下記記事にも書かれているが「Save Responses to a file」では要件に満たない場合、スクリプト系のPost Processorを使うと自在に制御ができる
今回は「JSR223 PostProcessor」をGroovyで使用してみる
Performance Testing: Upload and Download Scenarios with Apache JMeter
If you want total control which isn't achievable with the above options there is always a possibility to use scripting to manipulate response data.
For the Beanshell Post Processor “data” pre-defined variable is available. It is a byte array which contains server response for the parent sampler.
For JSR223 or BSF Post Processors a “prev” pre-defined variable exists. It stands for SampleResult class instance and exposes:
- 対象のSamplerに「JSR223 PostProcessor」を追加しスクリプトを記述する
任意のフォルダにファイルを保存するスクリプト例
※このくらいなら「Save Responses to a file」でもできるのだが、実際はスクリプト内では変数の使用や条件分岐なども可能で自由度が高い
new File("D:\\app\\download" + prev.getURL().getFile()).append(prev.getResponseData());
Samplerの実行結果(SampleResult)がprev変数に格納されておりgetResponseData()でボディがgetResponseHeaders()でヘッダが取得できたりする
- 実行~結果確認
シナリオは成功し意図したフォルダに意図したファイル名で保存されている
なお今回のケースでは関係ないが、直接リンクではなくWebアプリ側でファイルを生成し中身を返すようなケースでは「Content-Disposition」レスポンスヘッダの「filename」にファイル名がセットされていることもあり、その場合は以下のようにしてファイル名を取得~保存できる
// 日本語ファイル名で文字化けしている場合は変換
def responseHeaders = new String(prev.getResponseHeaders().getBytes("ISO-8859-1"), "UTF-8");
// ファイル名を取得
def filename = "";
responseHeaders.eachLine {
def m = (it =~ /filename="(.*)"/);
if (m.find()) {
filename = m.group(1);
}
}
// ファイルに書出し
if (filename.length > 0) {
new File(filename).append(prev.getResponseData());
}
終わりに
レスポンスデータを保存したい場合、簡易なら「Save Responses to a file」で十分だし、必要なら「JSR223 PostProcessor」を使えば自在に制御が可能なことがわかった
あとはGroovyにももう少し詳しくなりたいところ(Gradle DSLのベースでもあることだし)
余談
シナリオ記録時にファイルをダウンロードするところで「500 Internal Server Error」が出るかシナリオとしては記録されているので無視してよい、と考えている
※「HTTP(S) Test Script Recorder」(プロキシ)のところでレスポンスデータを解釈できずにエラーになっているのだろう