はじめに
スクリプトの単体テストにServerspecを使ってみました。
バージョン
記事作成で用いたOS・モジュールのバージョンはこちらです。
- Windows 7 Pro SP1 32bit 日本語版
- ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-mingw32]
- rspec (3.4.0)
- rspec-core (3.4.1)
- rspec-its (1.2.0)
- serverspec (2.26.0)
- specinfra (2.47.0)
※rubyスクリプトは全て文字コードを「UTF-8」で保存しています。
※バッチファイルは「Shift-JIS」で保存しています。
テスト対象スクリプト
例として、次のバッチファイルに対してブラックボックステストを実施したいと思います。
C:\job\script\test.cmd
@ECHO OFF
set PATH_D_SCR=%~dp0
set PATH_D_SCR=%PATH_D_SCR:~0,-1%
set MY_NAME=%~n0
set MY_EXTENTION=%~x0
set MY_NAME_EXT=%MY_NAME%%MY_EXTENTION%
set ERR_NO=%1
If "%ERR_NO%" == "" (
set ERR_NO=200
)
ruby %PATH_D_SCR%\ruby\test.rb %ERR_NO%
set RET_CD=%ERRORLEVEL%
If %RET_CD% NEQ 0 (
If %RET_CD% NEQ 10 (
Echo [%MY_NAME_EXT%] エラーが発生しました。:%RET_CD%
set RET_CD=20
GOTO :END
) Else (
Echo [%MY_NAME_EXT%] 警告が発生しました。:%RET_CD%
set RET_CD=10
GOTO :END
)
) Else (
Echo [%MY_NAME_EXT%] 正常終了しました。:%RET_CD%
set RET_CD=0
GOTO :END
)
:END
exit %RET_CD%
バッチファイルから呼ばれるコマンドです。
C:\job\script\ruby\test.rb
#!/usr/local/bin/ruby
i = ARGV[0]
i = 0 if i.nil?
puts "===<<< TEST.RB -> EXIT(#{i}) >>>==="
exit("#{i}".to_i)
SpecInfraの修正
SpecInfraを少しだけ修正します。
lib\specinfra\backend\cmd.rb
13a14,17
>
> # MODIFIED
> script << "; exit $LASTEXITCODE"
>
28a33,36
>
> # MODIFIED
> status = status.exitstatus
>
45,46c53,60
< architecture = @example.metadata[:architecture] || get_config(:architecture)
<
---
> # MODIFIED
> # architecture = @example.metadata[:architecture] || get_config(:architecture)
> if @example.respond_to?(:metadata)
> architecture = @example.metadata[:architecture]
> else
> architecture = get_config(:architecture)
> end
> architecture = Specinfra.configuration.architecture if architecture.nil? && ! Specinfra.configuration.architecture.nil?
テストケースの作成
spec_helper.rbで「serverspec」を指定します。
C:\job\test\spec\spec_helper.rb
require 'serverspec'
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
テストケースを作成します。
C:\job\test\spec\test_spec.rb
require "spec_helper"
set :backend, :cmd
set :os, :family => 'windows'
Specinfra.configuration.architecture = :i386
CMD_PATH = "C:\\job\\script\\test.cmd"
context "正常系の確認".encode("Windows-31J") do
describe command("#{CMD_PATH} 0") do
its(:stdout) { should match /#{"正常終了しました。".encode("Windows-31J")}/ }
its(:stdout) { should match /EXIT\(0\)/ }
its(:exit_status) { should eq 0 }
end
end
context "警告系の確認".encode("Windows-31J") do
describe command("#{CMD_PATH} 10") do
its(:stdout) { should match /#{"警告が発生しました。".encode("Windows-31J")}/ }
its(:stdout) { should match /EXIT\(10\)/ }
its(:exit_status) { should eq 10 }
end
end
context "異常系の確認".encode("Windows-31J") do
describe command("#{CMD_PATH} 20") do
its(:stdout) { should match /#{"エラーが発生しました。".encode("Windows-31J")}/ }
its(:stdout) { should match /EXIT\(20\)/ }
its(:exit_status) { should eq 20 }
end
end
テストケースの実行
それでは単体テストを実行してみます。
PS C:\job\test> rspec -fd .\spec\cmd\test_spec.rb
正常系の確認
Command "C:\job\script\test.cmd 0"
stdout
should match /正常終了しました。/
stdout
should match /EXIT\(0\)/
exit_status
should eq 0
警告系の確認
Command "C:\job\script\test.cmd 10"
stdout
should match /警告が発生しました。/
stdout
should match /EXIT\(10\)/
exit_status
should eq 10
異常系の確認
Command "C:\job\script\test.cmd 20"
stdout
should match /エラーが発生しました。/
stdout
should match /EXIT\(20\)/
exit_status
should eq 20
Finished in 2.31 seconds (files took 1.14 seconds to load)
9 examples, 0 failures
PS C:\job\test>
問題なく日本語での標準出力メッセージ判定と戻り値判定ができました。