テストフレームワークPesterを使ってみる

テストの仕方ってよくわからないんですが、PowerShellのテストフレームワークを探していたら[Pester](https://github.com/pester/Pester)というのを見つけたので、これを使ってみます。

## Pesterをインストールする
３年前の記事だけど、[PowerShellの単体テストフレームワーク / どらちゃんのポッケ](http://sleeping-micchi.hatenablog.com/entry/20121020/1350736643)を参考にインストール。

``` powershell
(*'-') >> (new-object Net.WebClient).DownloadString("http://bit.ly/GetPsGet") | iex
Downloading PsGet from https://github.com/psget/psget/raw/master/PsGet/PsGet.psm1
PsGet is installed and ready to use
USAGE:
    PS> import-module PsGet
    PS> install-module PsUrl

For more details:
    get-help install-module
Or visit http://psget.net
(*'-') >> import-module PsGet
(*'-') >> install-module PsUrl
"C:\Users\IEUser\Documents\WindowsPowerShell\Modules" is added to the PSModulePath environment variable
Module PsUrl was successfully installed.
(*'-') >> install-module Pester
Module Pester was successfully installed.
(*'-') >> import-module Pester
```

これで使えるようになった。毎回モジュールを読み込むのも面倒なので、`$profile`ファイルの最後にでも次の２行を足しておく。

``` powershell
Import-Module PsGet
Import-Module Pester
```

## テストの準備
テストコードの作成は`New-Fixture`で。

最初の引数はカレントディレクトリを起点としたテストコードの作成場所。２番目の引数はテストコードファイルのベースネーム。同じ名前にするとややこしいね。

``` powershell
(*'-') >> New-Fixture chkopt chkopt


    ディレクトリ: C:\Users\home\chkopt


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2015/11/03     16:06             27 chkopt.ps1
-a----       2015/11/03     16:06            249 chkopt.Tests.ps1


(*'-') >>
```

バージョンが違うのか、さっきの記事の内容とは少しコードが違うので今度は[Windows PowerShellでBDD / 株式会社SHIFT](http://softwaretest.jp/labo/tech/labo-274/)を参考に。

テスト対象テンプレート

``` chkopt.ps1
function chkopt {

}
```

テストコードテンプレート

``` chkopt.Test.ps1
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

Describe "chkopt" {
    It "does something useful" {
        $true | Should Be $false
    }
}
```

## テストコードを書いてみる
オプションチェックの関数をテストしてみましょう。シェルスクリプトの引数として与えられた値が、オプションとして有効か否かを判定する関数です。

`$opt_sw`にスクリプトの引数（例えばargs[0]）、`$opt_lst`に有効なオプションリストを配列で与えると、`$ret_code`でチェックの結果を返します。

有効なオプションであればオプションリストの何番目であるかを整数で、無効なオプションであれば0を返します。

``` chkopt.ps1
function Check-OptionSwitch($opt_sw, $opt_lst) {
  $ret_code = 0
  for ($loop_n = 0; $loop_n -lt $opt_lst.length; $loop_n++) {
    if ($opt_sw -ceq $opt_lst[$loop_n]) {$ret_code = 1 + $loop_n}
  }
  return $ret_code
}
```

テストコードはDescribeで囲まれた中の条件を書き換えます。

1. Describeに続けてテストするモジュールの識別名"chkopt"を書きます。今回はひとつしかテストしないのでどうでもいいんですが、複数テストをするとどの部分かわからなくなるので一意な名前にしましょう。

2. Itに続けてテストの内容を書いておきます。出力結果がOKかNGかしか出ないので、実際にどんな条件でテストしているかを書いておくとわかりやすいです。

3. で、{}内が実際のテストの中身。"| Should Be"の前後（左辺と右辺）をそれぞれ書き換えます。左辺にテストする関数とそれに与える引数を、右辺に期待する結果を記述します。

今回はDescribeの前に`$option_list`で設定した"-a", "-v", "-h"の三つに対して、それぞれ1, 2, 3が返されることを確認します。なお、今回の関数は大文字と小文字を区別するようにしたので、"-A"を与えたときに無効と判定し0を返すことも確認します。

``` chkopt.Test.ps1
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

$option_list = @("-a", "-v", "-h")
Describe "chkopt" {
    It "１番目の-aオプションは1" {
        Check-OptionSwitch "-a" $option_list | Should Be 1
    }
    It "２番目の-vオプションは2" {
        Check-OptionSwitch "-v" $option_list | Should Be 2
    }
    It "３番目の-hオプションは3" {
        Check-OptionSwitch "-h" $option_list | Should Be 3
    }
    It "オプションに存在しない-Aは0" {
        Check-OptionSwitch "-A" $option_list | Should Be 0
    }
    It "オプションが存在しない時は0" {
        Check-OptionSwitch "" $option_list | Should Be 0
    }
}
```

## テストしてみる
テスト実行はchkopt.Test.ps1または`Invoke-Pester`で。複数のテストスクリプトを一気に実行するときは`Invoke-Pester`を使います。

``` powershell
(*'-') >> .\chkopt.Tests.ps1
Describing chkopt
 [+] １番目の-aオプションは1 46ms
 [+] ２番目の-vオプションは2 52ms
 [+] ３番目の-hオプションは3 40ms
 [+] オプションに存在しない-Aは0 126ms
 [+] オプションが存在しない時は0 231ms
(*'-') >>
```

無事にテストが通りました。

ちなみにテストがエラーになると、エラー部位を赤字で教えてくれます。

``` powershell
(*'-') >> .\chkopt.Tests.ps1
Describing chkopt
 [+] １番目の-aオプションは1 58ms
 [+] ２番目の-vオプションは2 42ms
 [-] ３番目の-vオプションは3 90ms
   Expected: {3}
   But was:  {2}
   at line: 14 in C:\Users\home\chkopt\chkopt.Tests.ps1
   14:         Check-OptionSwitch "-v" $option_list | Should Be 3
 [+] オプションに存在しない-Aは0 58ms
 [+] オプションが存在しない時は0 41ms
(*'-') >>
```

テストコードを書くときにコピペしたら３番目の条件指定を間違えちゃった。

とりあえず、一番簡単な使い方がこんなところかな。