はじめに
そこそこの規模のシステムのコンポーネント間のテストにTurnipがどの程度適合するか試しています。各コンポーネント間でのデータはHTTP APIコールやファイルなどでやりとりするようなシステムが前提です。筆者はRubyについては初心者に毛が生えない程度ですがその他よさそうなツールがないので見よう見まねで使おうという算段です。
目的
- (1)テストケース作成→(2)テスト準備→(3)テスト実行→(4)テスト結果記入 のステップを極力自動化したい
- (1)(4)のためにExcelでテスト仕様書を書くのをやめたい
- (2)のアウトプットが(3)で直接実行可能なように記述できる
- (2)のアウトプットが可読性が高く(1)の代わりになる
- (3)のアウトプットがそのまま(4)の代替になる
- (1)(4)のためにExcelでテスト仕様書を書くのをやめたい
利用ツールの検討
上記目的を満たすものとして、受入テストに使うような、要求仕様にたいしてブラックボックステストをするようなツールの利用について検討をしました。
各ツールについての検討
-
ディシプリンド・アジャイル・デリバリー エンタープライズ・アジャイル実践ガイド(2013)
- Fitnesse ... Java製、管理UI、Wikiでテストケース記述、直近1年の日本語情報少ない
- Twist ... IDE、直近1年の日本語情報がほぼない
- JBehave ... Java製、大変そう https://goo.gl/rnmyMZ
- Concordion ... Java製、HTMLでのアサーション https://goo.gl/PWdeu4
- Cucumber ... Ruby製、日本語情報は他にくらべれば多い
ということで日本語でシナリオが記述できて目的とも合致しやすそうなCucumberの利用を検討しましたが、以下の記事を読んで、さらにとっつきやすそうなTurnipを利用することにしました。
Turnip のインストールとテスト
こちらを参考にインストールを進めます。
Turnip について (1) / まずは動かす
環境
- Amazon Linux AMI release 2016.09
- kernel: 4.4.41-36.55.amzn1.x86_64
手順
rubyのバージョン確認
$ ruby -v
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
事前準備
Gemfile
$ mkdir turnip_example
$ cd turnip_example/
$ mkdir spec
$ cat > Gemfile
source 'https://rubygems.org'
gem 'turnip'
.rspec
$ cat > .rspec
-r turnip/rspec
--color
--format documentation
spec_helper.rb
$ cat > spec/spec_helper.rb
require 'rubygems'
require 'bundler/setup'
Dir.glob("spec/steps/**/*steps.rb") { |f| load f, true }
Bundle Exec Rspec spec//.featureが失敗する件
のよう .rspec に turnipだけしか記載しないと実行に失敗しました。
rspecのフォーマットについては RSpecを斬る > フォーマット指定 を参考にしました。
bundleがないのでインストール
$ gem install bundler
Fetching: bundler-1.14.3.gem (100%)
Bundler and RubyGems.org are free for anyone to use, but maintaining them costs more than $25,000 USD every month. Help us cover those costs so that we can keep the gem ecosystem free for everyone: https://ruby.to/support-bundler
Successfully installed bundler-1.14.3
Parsing documentation for bundler-1.14.3
Installing ri documentation for bundler-1.14.3
Done installing documentation for bundler after 5 seconds
1 gem installed
ただインストールしただけでは動かないので以下を参考に追加インストール
EC2でBundle Installすると、io/consoleエラーになる
Amazon Linuxでbundle installのエラーに対処する
$ sudo yum install -y ruby-devel
$ gem install io-console
ようやくturnipのインストールができます
$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/............
Fetching version metadata from https://rubygems.org/..
Resolving dependencies...
Rubygems 2.0.14.1 is not threadsafe, so your gems will be installed one at a time. Upgrade to Rubygems 2.1.0 or higher to enable parallel gem installation.
Installing diff-lcs 1.3
Installing multi_json 1.12.1
Installing rspec-support 3.5.0
Using bundler 1.14.3
Installing gherkin 2.12.2 with native extensions
Installing rspec-core 3.5.4
Installing rspec-expectations 3.5.0
Installing rspec-mocks 3.5.0
Installing rspec 3.5.0
Installing turnip 2.1.1
Bundle complete! 1 Gemfile dependency, 10 gems now installed.
Bundled gems are installed into ./vendor/bundle.
このあとbundle exec rspecするとインストールされたmulti_jsonが毎回WARNINGを吐いてうっとおしいのでvendor/bundle以下のファイルを直接コメントアウトしました。
MultiJson is using the default adapter (ok_json). We recommend loading a different JSON library to improve performance.
featuresファイルの作成
$ mkdir spec/features
$ cat > spec/features/aggregation.feature
テストとして、以下のようなウェブサーバにユーザからリクエストが飛んで、そのリクエストのログが集計用の別コンポーネントで正常に集計されているかどうかを確認する機能のシナリオを作成しました。
Feature: リクエスト集計
Background:
Given 各サービスが正常動作
Scenario: 1リクエストが正常に集計される
Given 1ユーザが1リクエスト
When 集計処理が完了
Then 集計結果に反映
Scenario: 複数リクエストが正常に集計される
Given 3ユーザが各々5リクエスト
When 集計処理が完了
Then 集計結果に反映
Scenario: 不正なリクエストは集計から除外される
Given 不正なリクエスト
When 集計処理が完了
Then 集計結果に反映されない
$ mkdir spec/steps
$ cat > spec/steps/aggregation_steps.rb
各ステップは以下のように定義しました。
# coding: utf-8
step "各サービスが正常動作" do
# ウェブサービスの正常動作確認
# 集計サービスの正常動作確認
end
step "1ユーザが1リクエスト" do
# 期待する結果の差分は1リクエスト
@expected_diff = 1
# 現在のリクエスト数を取得する処理
@original_count = 1323
# サーバへのHTTPリクエスト実施
end
step "3ユーザが各々5リクエスト" do
# 期待する結果の差分は1リクエスト
@expected_diff = 15
# 現在のリクエスト数を取得する処理
@original_count = 1309
# サーバへのHTTPリクエスト実施
end
step "不正なリクエスト" do
# 期待する結果の差分は0リクエスト
@expected_diff = 0
# 現在のリクエスト数を取得する処理
@original_count = 1324
# サーバへのHTTPリクエスト実施
end
step "集計処理が完了" do
# 集計処理完了待ち
# 集計処理完了後結果取得
@current_count = 1324
end
step "集計結果に反映" do
@actual_diff = @current_count - @original_count
expect(@actual_diff).to be == @expected_diff
end
step "集計結果に反映されない" do
@actual_diff = @current_count - @original_count
expect(@actual_diff).to be == 0
end
実行します
$ bundle exec rspec
リクエスト集計
1リクエストが正常に集計される
Given 各サービスが正常動作 -> Given 1ユーザが1リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
複数リクエストが正常に集計される
Given 各サービスが正常動作 -> Given 3ユーザが各々5リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
不正なリクエストは集計から除外される
Given 各サービスが正常動作 -> Given 不正なリクエスト -> When 集計処理が完了 -> Then 集計結果に反映されない
Finished in 0.0047 seconds (files took 0.22233 seconds to load)
3 examples, 0 failures
意図的にエラーを起こすようにした例(長い)
"集計処理が完了"の@current_count値をいじって意図的にエラーを出すようにします。
$ bundle exec rspec
リクエスト集計
1リクエストが正常に集計される
Given 各サービスが正常動作 -> Given 1ユーザが1リクエスト -> When 集計処理が完了 -> Then 集計結果に反映 (FAILED - 1)
複数リクエストが正常に集計される
Given 各サービスが正常動作 -> Given 3ユーザが各々5リクエスト -> When 集計処理が完了 -> Then 集計結果に反映 (FAILED - 2)
不正なリクエストは集計から除外される
Given 各サービスが正常動作 -> Given 不正なリクエスト -> When 集計処理が完了 -> Then 集計結果に反映されない (FAILED - 3)
Failures:
1) リクエスト集計 1リクエストが正常に集計される Given 各サービスが正常動作 -> Given 1ユーザが1リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
Failure/Error: expect(@actual_diff).to be == @expected_diff
expected: == 1
got: -2
# spec/steps/aggregation_steps.rb:40:in `block in <top (required)>'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/execute.rb:25:in `step'
# ./spec/features/aggregation.feature:9:in `run_step'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `instance_eval'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `run_step'
# ./spec/features/aggregation.feature:8:in `block (4 levels) in run_feature'
# ./spec/features/aggregation.feature:7:in `each'
# ./spec/features/aggregation.feature:7:in `block (3 levels) in run_feature'
# ./spec/features/aggregation.feature:9:in `集計結果に反映'
2) リクエスト集計 複数リクエストが正常に集計される Given 各サービスが正常動作 -> Given 3ユーザが各々5リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
Failure/Error: expect(@actual_diff).to be == @expected_diff
expected: == 15
got: 12
# spec/steps/aggregation_steps.rb:40:in `block in <top (required)>'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/execute.rb:25:in `step'
# ./spec/features/aggregation.feature:14:in `run_step'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `instance_eval'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `run_step'
# ./spec/features/aggregation.feature:13:in `block (4 levels) in run_feature'
# ./spec/features/aggregation.feature:12:in `each'
# ./spec/features/aggregation.feature:12:in `block (3 levels) in run_feature'
# ./spec/features/aggregation.feature:14:in `集計結果に反映'
3) リクエスト集計 不正なリクエストは集計から除外される Given 各サービスが正常動作 -> Given 不正なリクエスト -> When 集計処理が完了 -> Then 集計結果に反映されない
Failure/Error: expect(@actual_diff).to be == 0
expected: == 0
got: -3
# spec/steps/aggregation_steps.rb:45:in `block in <top (required)>'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/execute.rb:25:in `step'
# ./spec/features/aggregation.feature:19:in `run_step'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `instance_eval'
# ./vendor/bundle/ruby/2.0/gems/turnip-2.1.1/lib/turnip/rspec.rb:44:in `run_step'
# ./spec/features/aggregation.feature:18:in `block (4 levels) in run_feature'
# ./spec/features/aggregation.feature:17:in `each'
# ./spec/features/aggregation.feature:17:in `block (3 levels) in run_feature'
# ./spec/features/aggregation.feature:19:in `集計結果に反映されない'
Finished in 0.01192 seconds (files took 0.18849 seconds to load)
3 examples, 3 failures
Failed examples:
rspec ./spec/features/aggregation.feature:6 # リクエスト集計 1リクエストが正常に集計される Given 各サービスが正常動作 -> Given 1ユーザが1リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
rspec ./spec/features/aggregation.feature:11 # リクエスト集計 複数リクエストが正常に集計される Given 各サービスが正常動作 -> Given 3ユーザが各々5リクエスト -> When 集計処理が完了 -> Then 集計結果に反映
rspec ./spec/features/aggregation.feature:16 # リクエスト集計 不正なリクエストは集計から除外される Given 各サービスが正常動作 -> Given 不正なリクエスト -> When 集計処理が完了 -> Then 集計結果に反映されない
まとめ
作成中