ちょっとタイトルで何が言いたいのかわからない
自作module内で定義した関数で他のサービス等に依存するCmdlet(ex. Invoke-WebRequest
)を使用する際に、それをテストする方法で少しつまづいた、というお話です。
検証環境
- OS: Windows10 Pro
- Powershell Version: 5.0
- Pester Vesion: 不明……
- VisualStudio2015のPowerShell Tools for Visual Studio2015 Ver.3.0.399付属のもの
結論
Describe
を InModuleScope "{モジュール名}"
に内包することで実現できます。
# たとえばこういう階層でコードがあったとする。。。
# root/
# ├ src.ps1
# ├ modules/
# │ └ module.psm1
# └ tests/
# ├ src.tests.ps1
# └ module.tests.psm1
# この例でやりたいこと:
# 1. module.psm1ではGet-IsSunnyDay関数を定義する。
# 2. Get-IsSunnyDayは、Invoke-WebRequest Cmdletを使用してお天気情報APIへアクセスし、「晴れ」が返されれば$trueを、それ以外の天候が返されれば$falseを、サービスが停止されている等で HTTPSTATUSCODE 200 以外が返された場合は例外を投げる仕様とする。
# 3. このテストではお天気情報APIがもしも死んでしまった場合、ちゃんと例外が投げられるかどうかを確認したい。……ので、お天気APIへリクエストを投げるInvoke-WebRequestをMockしたい。
# こう書くとうまくいく
Get-Module "モジュール名" | Remove-Module -Force
Import-Module "モジュール名またはモジュールファイルへの相対パス" -Force
InModuleScope "モジュール名" {
Describe "Get-IsSunnyDay" {
Context "Exception" {
It "お天気情報APIが死んでる場合例外が投げられる" {
Mock Invoke-WebRequest { return @{StatusCode=404} }
{ Get-IsSunnyDay } | Should Throw
}
}
}
}
# うまくいかなかったのはこちら
Import-Module "モジュール名またはモジュールファイルへの相対パス" -Force
Describe "Get-IsSunnyDay" {
Context "Exception" {
It "お天気情報APIが死んでる場合例外が投げられる" {
# ちなみにMockの位置をItの外、Contextの外に出しても、Mock -ModuleName "モジュール名"と指定してもうまくいきませんでした。。。
Mock Invoke-WebRequest { return @{StatusCode=404} }
{ Get-IsSunnyDay } | Should Throw
}
}
}
ちなみに
- 今回は
Invoke-WebRequest
を例にしましたが、それに限らず、例えばls (Get-ChildItems)
等、色々なCmdletをMockできるみたいです。 - UnitTestの対象とするファイルが
.ps1
であれば、このような方法はとらなくてもよいようです。 (逆に、モジュールをテストする場合は必須になるのかな。。。)
参考にしたサイト様 / 記事等
-
Testing Script Modules with Pester - Hey, Scripting Guy! Blog (technet.microsoft.com)
https://blogs.technet.microsoft.com/heyscriptingguy/2015/12/17/testing-script-modules-with-pester/ -
Unit Testing within Modules - GitHub pester/Pester
https://github.com/pester/Pester/wiki/Unit-Testing-within-Modules