0.前置き

この記事はPowerShell Advent Calender 2012の17日目のエントリーです。
前日は@Chukiさんの「Active Directoryの管理なら 7/R2以降を使いましょう^^」でした。

今回は、PowerShellのユニットテストの内容を書こうと意気込んでいましたがなんと@fsugiyamaさんが2011年のAdventCalenderで書いていらっしゃいました。今回はせっかくなので導入編は省いて、マニュアルっぽくまとめてみたいと思います。

0-1.Pesterの紹介

BDDスタイルテスティングフレームワークです。
・本家のサイトはこちらのgithubで
・日本語だと@fsugiyamaさんのPester – BDD style testing framework for PowerShell

0-2.コンテンツ

マニュアルになるように以下の順序に沿って整理していきます。
記載の分類は、「JUnit実践入門」、記載内容は、Pesterの解説ページなどを参考にしています。

  • 1. テストの準備
  • 2. アサーション
  • 3. テストランナー
  • 4. テストのコンテキスト
  • 5. モック
  • 6. CIとの統合

1. テストの準備

Get-Hogeというコードの作成と、これに対するテストコードの作成を行いましょう。
まずはPesterの機能を用いてスケルトンと呼ばれるテンプレートを作成します。
[sourcecode language=”powershell”]
PS D:\xxx> New-Fixture scripts Get-Hoge
Creating => scripts\Get-Hoge.ps1
Creating => scripts\Get-Hoge.Tests.ps1
PS D:\xxx>
[/sourcecode]
Get-Hoge.ps1が本体のコードを格納するファイル、Get-Hoge.Tests.ps1がテストコードを格納するファイルになります。

2. アサーション

続いて、アサーション(検証方法)を整理していきます。
Pesterでは、「Should」オブジェクトを利用して検証を行います。「Should」のメンバーには以下のものがあります。
多くが内部的にはPowerShellの標準機能をそのまま利用しています。

Be

2つのオブジェクトを比較します。
[sourcecode language=”powershell”]
$actual="こんにちは"
$actual.should.be("こんにちは") // 成功する
[/sourcecode]

Hava_Count_Of

IEnumerable型オブジェクトの件数を検証します。
[sourcecode language=”powershell”]
@(1,2,3,4).should.have_count_of(5) # 失敗する
[/sourcecode]

Exist

PSドライブ内に対象が存在するかどうかチェックします。
ファイル・フォルダーの存在チェックや、レジストリー値の存在チェックなどなんでもOK。
Test-Pathと同等の検証機能です。
[sourcecode language=”powershell”]
"C:\hogehoge\fuga".should.exist()
[/sourcecode]

Match

正規表現を利用して2つのオブジェクトを比較。
PowerShellの正規表現と同等の検証機能。
[sourcecode language=”powershell”]
"192.168.1.1".should.match("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") # 成功
[/sourcecode]

Be_Like

ワイルドカードを利用して2つのオブジェクトを比較。
[sourcecode language=”powershell”]
"PowerShell".should.be_like("P*S*") # 成功
[/sourcecode]

3. テストランナー

テストを実行するときは、Invoke-Pesterを利用します。
このコマンドを利用すれば、指定したフォルダー以下にあるテスト用のファイルを再帰的に探し実行してくれます。
オプションを指定することによって、テスト結果をNUnitのレポート形式(?)にて出力できます。
[sourcecode language=”powershell”]
Invoke-Pester -OutputXml "TestResults.xml"
[/sourcecode]
実行結果は以下のように表示されます。
result

4. テストのコンテキスト

テストケースが複数になった場合は、グループ化して可読性をあげる必要があります。
そのためにPesterでは、Describe、Context、Itを利用します。
Itが1テストケースに相当します。ContextがItをまとめたもの。DescribeがContextをまとめたものです。
[sourcecode language=”powershell”]
Describe "Exec-Calc" {
Context "例外処理の確認"{
It "引数がnullかチェックする"{
#…
}

It "引数が数値かチェックする"{
#…
}
}

Context "本体処理の確認"{
It "加算処理を実行する"{
#…
}

It "減算処理を実行する"{
#…
}
It "除算処理を実行する"{
#…
}

It "乗算処理を実行する"{
#…
}
}
}
[/sourcecode]
テストの実行結果はこのようにグループ化されて表示されます。
result2

5. モック

PowerShellは利用されるシチュエーション上、外部モジュールとのやりとりが気持ち多くなる気がします。
ユニットテストを行う場合、その外部モジュールの挙動をシミュレーションするモックが重要になります。
モックの作成方法と、モックの検証方法は以下の通りです。
[sourcecode language=”powershell”]
#モックを作成
Mock Get-Hoge { return 2 }

#モックを作成(パラメータによってモックを起動するかどうか指定する)
Mock Get-Hoge {return 7} -parameterFilter{$val -eq 10}

#モックの検証(-verifiablez属性を付与したモックが利用されたかどうか)
Mock Get-Hoge -verifiable {return 7}
Assert-VerifiableMocks

#モックの検証(モックが指定回数呼ばれたかどうか)
Assert-MockCalled Get-Hoge-Times 10
[/sourcecode]

6. CIとの統合

PesterはさまざまなCIツールと統合することができます。
PowerShellのコマンドで走らせてもよいのですが、batがあります。
[sourcecode language=”bash”]
./pester.bat
[/sourcecode]
もちろんNunitと同じ形式でテスト結果を出力できます。(「3.テストランナー」参照)

7.最後に

PowerShellのコードもユニットテストをしようということで、Pesterを紹介しました。
なるべく全機能を紹介するようしました。
これだけあれば、あとはテストコードを書き始めるだけ!

明日は、@ichiohtaさんです!お願いしますー。