-
Notifications
You must be signed in to change notification settings - Fork 0
シナリオ実行の流れ
このハンズオンでは、ソフトウェアの受け入れテストツールであるcucumberからNetTesterを連携する形で呼び出し、 ネットワークの構成やテストノードの繋ぎこみをテストに合わせて変更しながら、テストノードからパケットを送信するといった処理を行います。
NetTesterはRubyからライブラリとして、あるいはShellなどからコマンドとして利用できる、 結線制御や仮想ホスト制御を含んだツールです。
NetTesterはテストフレームワーク自体は含んでいません。 RubyやShellから呼ぶ、あるいはRESTで呼ぶことができるのため、既存テストフレームワークと連携可能である、という表現が正確です。
既存テストフレームワークとしては、cucumberなどがあります。
Ruby製の受け入れテストフレームワークで、試験仕様を日本語で記述できる特徴があります。
日本語でテストを記述する、というのはイメージしにくいかもしませんが、 特定の日本語の文字列に対応するRubyコード(step)を定義しておいて、テストケース(feature)に書かれた日本語に引っかかったstepを実行する、 という仕組みで実現されています。
今回のハンズオン環境のテストシナリオのディレクトリ、ファイルは以下のような構成になっています。
scenario
├── Gemfile [rubyのパッケージ管理ファイル]
├── Gemfile.lock [rubyのパッケージ管理ファイル]
├── Rakefile [タスク定義ファイル]
└── features [シナリオファイルのディレクトリ]
├── *.feature [各シナリオファイル(今回はテストの視点に合わせてuser/、admin/の下に作成)
├── factories.rb [テスト用ネットワーク、テスト用ノード定義ファイル]
├── step_definitions [シナリオで実際に実行されるプログラムコードのディレクトリ]
│ └── *.rb [シナリオで実際に実行されるプログラムコード]
└── support [補助ファイル]
├── aruba.rb [補助ライブラリのファイル]
├── factory_girl.rb [テスト用ネットワーク、テスト用ノード定義を簡単にするライブラリのファイル]
├── hooks.rb [シナリオ実行時、シナリオ終了時のタイミングで行う処理などを記載したファイル]
├── test_node.rb [テスト用ノードクラスのファイル]
└── tester_sets.rb [拠点定義ファイル]
テストの記述と実行の中心となるファイルは、featureファイルとstepファイルです。
featureファイルには、機能に対し、何をしたときにどのような振る舞いをすべきかを記載します。 先述の通り、ここには日本語も記述することができます。
例えば、このシステム(ネットワーク)ではユーザが自分のpcからwebで検索ができるべきである、という機能要件(通信要件)のテストを定義するには、 以下のように記述します。
$ cat features/user/user_pc_to_internet_host/web.feature
Feature: Google 検索
開発者として、
Google で検索したい
なぜなら開発するときによく調べものをするから
Scenario: Web ブラウザで Google を開く
Given 社内 PC
And インターネット上のサーバ
When 社内 PC にログイン
And ブラウザでインターネット上のサーバの Google のページを開く
Then Google のトップページが表示
stepファイルには、featureファイルを実行(Scenario、Given、Andなどの記述が該当)していく際に実際に動作するrubyのコードを記述します。 featureに記載された内容に対するstepは1ファイルである必要はなく、複数のファイルに分ける事が可能です。
例えば上記のweb.featureに対するstepは以下のようになっています。
- ホストの定義 (後続stepで使うため、変数にホストを代入) の技術
$ cat features/step_definitions/virtual_host.rb
# coding: utf-8
Given(/^社内 PC$/) do
@user_pc = TestNode.new(attributes_for(:user_pc))
end
-- snip --
Given(/^インターネット上のサーバ$/) do
@internet_host = TestNode.new(attributes_for(:internet_host))
end
-- snip --
- ユーザのアクションの記述
$ cat features/step_definitions/google_steps.rb
# coding: utf-8
When(/^ブラウザでインターネット上のサーバの Google のページを開く$/) do
cd('.') do
@internet_host.exec("rm -f /tmp/index.html; echo '<title>Google</title>' | tee /tmp/index.html", sync: true)
@https_service = @internet_host
@https_service.exec("ruby -rwebrick -rwebrick/https -e 'WEBrick::HTTPServer.new(:DocumentRoot => \"/tmp\", :Port => 443, :SSLEnable => true, :SSLCertName => [[\"CN\", WEBrick::Utils::getservername]] ).start'")
@src_host.exec("sudo mkdir -p /etc/netns/#{@src_host.name}", sync: true)
@src_host.exec("echo '198.51.100.3 www.google.com' | sudo tee /etc/netns/#{@src_host.name}/hosts >/dev/null", sync: true)
@process_id = @src_host.exec('curl -L --insecure https://www.google.com/ | iconv -f SHIFT-JIS -t UTF8', delayed: true)
end
end
- ユーザのアクションの結果の記述
$ cat features/step_definitions/success_steps.rb
-- snip --
Then(/^Google のトップページが表示$/) do
result = @src_host.result(@process_id)
expect(result).to match(/<title>Google<\/title>/)
end
-- snip --
featureのGiven、Whenなどに記述された内容に関して、正規表現で一致したコードが実行される仕組みです。 これをシナリオに従い順番に実行していくことで、期待どおりの動作になるかも含め、プログラムで確認します。
なお、このstepは、複数のfeatureで共有して使い回すことができます。
$ bundle exec cucumber <featureファイル>
$ bundle exec rake