Skip to content

シナリオ実行の流れ

127.0.0.1 edited this page Feb 3, 2018 · 20 revisions

シナリオ実行の仕組み

このハンズオンでは、ソフトウェアの受け入れテストツールであるcucumberからNetTesterを連携する形で呼び出し、 ネットワークの構成やテストノードの繋ぎこみをテストに合わせて変更しながら、テストノードからパケットを送信するといった処理を行います。

NetTester

NetTesterはRubyからライブラリとして、あるいはShellなどからコマンドとして利用できる、 結線制御や仮想ホスト制御を含んだツールです。

NetTesterはテストフレームワーク自体は含んでいません。 RubyやShellから呼ぶ、あるいはRESTで呼ぶことができるのため、既存テストフレームワークと連携可能である、という表現が正確です。

既存テストフレームワークとしては、cucumberなどがあります。

cucumber

Ruby製の受け入れテストフレームワークで、試験仕様を日本語で記述できる特徴があります。

日本語でテストを記述する、というのはイメージしにくいかもしませんが、 特定の日本語の文字列に対応するRubyコード(step)を定義しておいて、テストケース(feature)に書かれた日本語に引っかかったstepを実行する、 という仕組みで実現されています。

cucumber テストシナリオのディレクトリ構成

今回のハンズオン環境のテストシナリオのディレクトリ、ファイルは以下のような構成になっています。

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ファイル

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ファイルの中身

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で共有して使い回すことができます。

cucumberの実行

$ bundle exec cucumber <featureファイル>

cucumberの実行 (全シナリオ)

$ bundle exec rake
Clone this wiki locally