この記事は最終更新から1年以上経過しています。 気をつけてね。
Cucumberは、"このようになっていてくれ"という内容を記述して、それを実際にやってみた結果を判断するツール。
featureとしてシナリオを記述
features/websv.feature
# language: ja
機能: 静的コンテンツ配信
シナリオ: 秒辺りのレスポンスが規定以上かチェック
前提: ウェブサーバアドレスが 127.0.0.1 のとき
もし: 10 台のクライアントが同時に 1000 アクセスした
ならば: サーバのレスポンスが 3000 rps以上で
かつ: レスポンスコード 5xx がない
とりあえずシナリオを作成し、cucumberを実行する。
# cucumber
Using the default profile...
# language: ja
機能: 静的コンテンツ配信
シナリオ: 秒辺りのレスポンスが規定以上かチェック # features/websv.feature:3
前提 ウェブサーバアドレスが 127.0.0.1 のとき # features/websv.feature:4
もし 10 台のクライアントが同時に 1000 アクセスした # features/websv.feature:5
ならば サーバのレスポンスが 3000 rps以上で # features/websv.feature:6
かつ レスポンスコード 5xx がない # features/websv.feature:7
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.002s
You can implement step definitions for undefined steps with these snippets:
前提 /^ウェブサーバアドレスが (\d+)\.(\d+)\.(\d+)\.(\d+) のとき$/ do |arg1, arg2, arg3, arg4|
pending # express the regexp above with the code you wish you had
end
もし /^(\d+) 台のクライアントが同時に (\d+) アクセスした$/ do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
ならば /^サーバのレスポンスが (\d+) rps以上で$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
ならば /^レスポンスコード (\d+)xx がない$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
If you want snippets in a different programming language,
just make sure a file with the appropriate file extension
exists where cucumber looks for step definitions.
これらを定義しなさいと促されるのでstepsを作成する。
steps作成
features/websv.steps.rb
# coding: utf-8
前提 /^: ウェブサーバアドレスが ([\w\.-]+) のとき$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
もし /^: (\d+) 台のクライアントが同時に (\d+) アクセスした$/ do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
ならば /^: サーバのレスポンスが (\d+) rps以上で$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
ならば /^: レスポンスコード (\d+)xx がない$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
"ウェブサーバアドレス" の所だけパラメータ抽出表現を変えて作成。
これで作成してみる。
# cucumber
Using the default profile...
# language: ja
機能: 静的コンテンツ配信
シナリオ: 秒辺りのレスポンスが規定以上かチェック # features/websv.feature:3
前提: ウェブサーバアドレスが 127.0.0.1 のとき # features/websv.steps.rb:2
TODO (Cucumber::Pending)
./features/websv.steps.rb:3:in `/^: ウェブサーバアドレスが ([\w\.-]+) のとき$/'
features/websv.feature:4:in `前提: ウェブサーバアドレスが 127.0.0.1 のとき'
もし: 10 台のクライアントが同時に 1000 アクセスした # features/websv.steps.rb:6
ならば: サーバのレスポンスが 3000 rps以上で # features/websv.steps.rb:10
かつ: レスポンスコード 5xx がない # features/websv.steps.rb:14
1 scenario (1 pending)
4 steps (3 skipped, 1 pending)
0m0.003s
テスト内容がpendingとなる。
pendingを実装していく
ベンチマークにhttperfを使うので、rubyバインディングhttperfrbを準備してスタート。
ウェブサーバアドレスが ([\w.-]+) のとき
# coding: utf-8
require 'open3'
require 'httperf'
前提 /^ウェブサーバアドレスが ([\w\.-]+) のとき$/ do |arg1|
@perf = HTTPerf.new( "server" => arg1, "uri" => "/")
end
(\d+) 台のクライアントが同時に (\d+) アクセスした
もし /^(\d+) 台のクライアントが同時に (\d+) アクセスした$/ do |arg1, arg2|
@perf.update_option("num-conns", arg1)
@perf.update_option("num-calls", arg2)
end
サーバのレスポンスが (\d+) rps以上で
ならば /^サーバのレスポンスが (\d+) rps以上で$/ do |arg1|
@results = HTTPerf::Parser.parse(@perf.run)
puts "INFO: Request_rate is " + @results[:request_rate_per_sec]
raise "server is too slow." if @results[:request_rate_per_sec].to_i < arg1.to_i
end
レスポンスコード (\d+)xx がない
ならば /^レスポンスコード (\d+)xx がない$/ do |arg1|
raise "Response code 5xx found!!" unless @results[:reply_status_5xx].to_i == 0
end
こんな感じでfeatures/websv.steps.rb
にて実装する。
cucumber実行結果
# cucumber
Using the default profile...
# language: ja
機能: 静的コンテンツ配信
シナリオ: 秒辺りのレスポンスが規定以上かチェック # features/websv.feature:3
前提ウェブサーバアドレスが 127.0.0.1 のとき # features/websv.steps.rb:5
もし10 台のクライアントが同時に 1000 アクセスした # features/websv.steps.rb:9
ならばサーバのレスポンスが 3000 rps以上で # features/websv.steps.rb:14
INFO: Request_rate is 16281.4
かつレスポンスコード 5xx がない # features/websv.steps.rb:20
1 scenario (1 passed)
4 steps (4 passed)
0m0.073s
想定仕様は3000rpsで、実際のレスポンスは16000rps。
非機能要件をクリアしていると言える。
付録:features/websv.steps.rb の全行
# coding: utf-8
require 'open3'
require 'httperf'
前提 /^ウェブサーバアドレスが ([\w\.-]+) のとき$/ do |arg1|
@perf = HTTPerf.new( "server" => arg1, "uri" => "/")
end
もし /^(\d+) 台のクライアントが同時に (\d+) アクセスした$/ do |arg1, arg2|
@perf.update_option("num-conns", arg1)
@perf.update_option("num-calls", arg2)
end
ならば /^サーバのレスポンスが (\d+) rps以上で$/ do |arg1|
@results = HTTPerf::Parser.parse(@perf.run)
puts "INFO: Request_rate is " + @results[:request_rate_per_sec]
raise "server is too slow." if @results[:request_rate_per_sec].to_i < arg1.to_i
end
ならば /^レスポンスコード (\d+)xx がない$/ do |arg1|
raise "Response code 5xx found!!" unless @results[:reply_status_5xx].to_i == 0
end