Serverspecを読めるようになるための最低限の文法まとめ
はじめに
インフラの単体テストで ServerSpec が使用されることがある。
ServerspecはRubyのテストフレームワークRSpecを拡張して作られておりdescribe, it, should, each などの構文は RubyやRSpecに由来 している。
本記事では、Serverspecを理解するために最低限の文法を整理した。
1. describe と it
describe service('nginx') do
it { should be_running }
end
| 構文 | 意味 |
|---|---|
describe |
テスト対象(文脈)を定義 |
it |
期待する状態を定義 |
should |
「〜であるべき」という期待 |
「describeで文脈を作り、itで期待を書く」 という設計思想を採用している。
2. should / should_not:期待値の評価
it { should be_enabled }
it { should_not be_disabled }
should / should_not は真偽値(True/False)を評価するために使う。
3. each:ループ
複数のパッケージやサービスをまとめてテストしたいとき、Rubyのeachを利用して動的に記述できる。
%w(httpd git curl).each do |pkg|
describe package(pkg) do
it { should be_installed }
end
end
| 構文 | 意味 |
|---|---|
%w() |
文字列配列リテラル(例:["httpd", "git", "curl"]) |
.each |
配列の要素を1つずつ取り出して繰り返す |
do ... end |
繰り返し処理のブロック構文 |
pkg |
ループ内で使う変数(各要素が順に入る) |
動作の流れ:
-
%w(httpd git curl)により3要素の配列を生成 -
.eachにより1要素ずつ取り出す - 各要素が
pkgに渡され、describe package(pkg)が評価される -
endでブロックが閉じられる
- 複雑な構成では
eachをネストして複数ロールや環境変数を繰り返すケースもある。
4. let と $変数名:変数
ServerspecはRubyで書かれているため、Rubyの変数やRSpec特有の変数スコープ管理が利用できる。
代表的なものが グローバル変数 $name と let構文。
# spec_helper.rb
$server_ip = "192.168.10.10"
# specファイル
describe interface('eth0') do
it { should have_ipv4_address("#{$server_ip}/24") }
end
上記のように $server_ip を使えば、複数ファイル間で共通の値を利用できる。
テストファイル内限定の変数を let で定義することができる。
let(:port) { 80 }
describe port(port) do
it { should be_listening }
end
| 種類 | スコープ | 用途 |
|---|---|---|
$global |
全ファイル共通 | 設定値(例:hosts.ymlなどから読み込む) |
let(:name) |
ファイル内限定 | 一時的・テスト専用の値定義 |
let は「呼び出されたタイミングで初めて実行される遅延評価」であり、
RSpecのテストをより安全に保つための仕組みである。
参考: RSpec let
5. shared_examples:共通テストの再利用
複数のサーバやロールで共通化できるテストを一箇所にまとめて再利用できる。
コードの重複を減らすことが目的。
# shared/packages.rb
shared_examples 'package check' do |packages|
packages.each do |pkg|
describe package(pkg) do
it { should be_installed }
end
end
end
# web_spec.rb
include_examples 'package check', %w(httpd git curl)
shared_examples で定義したブロックを
include_examples で読み込むだけで、複数環境に同じテストを適用できる。
6. command と its(:stdout)
describe command('curl -I localhost') do
its(:stdout) { should match /200 OK/ }
end
describe command() はシェルコマンドを実行するテスト。
出力結果を its(:stdout) で検証する。
| 構文 | 意味 |
|---|---|
command() |
実際にコマンドを実行 |
its(:stdout) |
標準出力の内容を検証対象にする |
match /regex/ |
正規表現で評価する |
参考: Serverspec command resource
7. context:条件別のdescribe
context 'on CentOS' do
describe package('httpd') do
it { should be_installed }
end
end
context は describe の別名だが、「条件(環境・設定)」を明示するために使われる。
参考: RSpec context
8. if:条件分岐
Rubyのif構文をそのまま利用できる。
OSや条件によって異なる検証をしたい場合などに使う。
service_name = os[:family] == 'centos' ? 'httpd' : 'nginx'
describe service(service_name) do
it { should be_running }
end
ブロック内で条件分岐をすることも可能:
%w(httpd nginx).each do |svc|
describe service(svc) do
it { should be_running } if svc == 'nginx'
end
end
| 構文 | 意味 |
|---|---|
if 条件 |
条件が真なら実行 |
unless 条件 |
条件が偽なら実行 |
? : |
三項演算子 |
9. its と match / include
設定ファイルなどの内容を検証する際に使う。
its(:content) はファイルの内容を取得し、
match や include で文字列・正規表現で確認する。
describe file('/etc/nginx/nginx.conf') do
its(:content) { should match /worker_processes/ }
its(:content) { should include "nginx" }
end
| 構文 | 検証内容 |
|---|---|
match /regex/ |
正規表現に一致すること |
include "文字列" |
指定文字列を含むこと |
Discussion