はじめに...
調査した内容を時系列にまとめた資料なので、その点ご了承ください。
目次
- 実行環境
- 実現したいこと
- 作業の流れ
- 例題
- (i) フォルダを作成する
- (ii) テスト対象のコードを準備する
- (iii) テストコードを作成する
- (iv) テスト実行コードを作成する
- (v) テスト
- まとめ
- 参考リンク
1. 実行環境
項目 | 情報 |
---|---|
OS | macOS 11.6 |
HW | MacBook Air (11-inch, Mid 2013) |
pwsh | 7.2.0 |
pester | 5.3.3 |
MDM環境 | microsoft intune |
2. 実現したいこと
- powershell でユニットテストを実施したい
3. 作業の流れ
以下の流れを元に例題を定めて実践する
i. フォルダ構成を検討する
ii. テスト対象のコードを準備する
- テスト項目毎にfunctionを分けてコードを作る
iii. テストコードを作成する
iv. テスト実行コードを作成する
v. テスト
4. 例題
割り算を行うfunctionのテストを行う
5. (i) フォルダを作成する
今回はテストを実行するにあたり、テスト対象のスクリプトとテストコードを分離して管理する。
分離するためにフォルダは以下の4つで構成した。
また、命名規則を定めることで分離した際の負荷を軽減する。
# | フォルダ名 | ファイル名 | 役割 |
---|---|---|---|
1 | src | <コード名>.ps1 | テスト対象コード |
2 | test-src | <コード名>.ps1 | テストコード |
3 | test-exec | <コード名>.Test-Exec.ps1 | テスト実行コード |
4 | test-result | <コード名>.Test-Exec.ps1 | テスト結果(4の結果出力される) |
テスト対象コード-Division.ps1
- 今回の構成
# | フォルダ名 | ファイル名 | 役割 |
---|---|---|---|
1 | src | Division.ps1 | テスト対象コード |
2 | test-src | Division.test.ps1 | テストコード |
3 | test-exec | Division.test-exec.ps1 | テスト実行コード |
4 | test-result | Division.test-result.xml | テスト結果(4の結果出力される) |
6. (ii) テスト対象のコードを準備する
テスト対象のコードは以下の通り、定数1000を引数で割る関数。
Division.ps1
function SampleFunction001{
param([int]$i)
1000/$i
}
7. (iii) テストコードを作成する
テストコードの構成は以下の通り、Itが実際のテスト内容を記述する箇所となる。
テスト内容を分類するためにDescribe(説明) > Context(環境)という順序で分類する。
## ContextをまとめるDescribe
Describe "<Describeの説明>" {
## 全てのContextが実行される前に1回だけ実行されるBeforeAll
BeforeAll {
}
## テスト(It)をまとめる Context
Context "<Contextの説明>"{
# 実際のテスト内容(It)
It "<Itの説明>"{
# 実際のテスト内容
It "<Itの説明>"{
# 実際のテスト内容
}
}
## 全てのContextが実行された後1回だけ実行されるBeforeAll
AfterAll {
}
}
テストコード-Division.Test.ps1
```console
Describe "Function-001" {
BeforeAll {
# テスト開始時の処理を記載する
# テスト対象のコードをロードする
# $PSCommandPathを用いてテスト対象コードの名前を指定
Write-Verbose "BeforeAll";
$BasePath = Join-Path $(Split-Path $(Split-Path $PSCommandPath -Parent) -Parent) "src";
$TargetCode = Join-Path "${BasePath}" $(Split-Path -Leaf $PSCommandPath).Replace(".Test","");
. $TargetCode;
Write-Verbose "LoadFunction ${TargetCode}"
}
# 正常系のテスト
Context "正常系"{
# 1000 を 100で割ったら10
It "[SampleFunction001]-N--[001]" {
SampleFunction001 -i 100| Should -Be 10
}
# 1000 を 200で割ったら5
It "[SampleFunction001]-N--[002]" {
SampleFunction001 -i 200| Should -Be 5
}
}
# 異常系のテスト
Context "異常"{
It "[SampleFunction001]-AN-[001]" {
# 1000 を 0で割ったら Throw ※{}で囲む
{SampleFunction001 -i 0}| Should -Throw
}
It "[SampleFunction001]-AN-[002]" {
# 引数の指定が無かったら Throw
{SampleFunction001 }| Should -Throw
}
}
AfterAll{
# テスト終了時の処理を記載する
Write-Verbose "AfterAll";
}
}
</div>
</detials>
### 8. (iv) テスト実行コードを作成する
テスト実行コードの構成は以下の通り。
実際には、Invoke-Pesterコマンドだけで実行可能だが、今回はテストコードのファイル名を$PSCommandPathを元に生成したり、実行時の出力内容を指定しているため、長めとなっている。
<details><summary>テスト実行コード-Division.Test-Exec.ps1</summary><div>
```console
$BasePath = $(Split-Path $(Split-Path $PSCommandPath -Parent) -Parent)
# $PSCommandPathを用いてテストコードのファイル名を指定
$TargetCode = Join-Path "${BasePath}" "test-src" $(Split-Path -Leaf $PSCommandPath).Replace("-Exec","");
# $PSCommandPathを用いてテスト結果(xml)のファイル名を指定
$Result = Join-Path "${BasePath}" "test-result" $(Split-Path -Leaf $PSCommandPath).Replace("-Result","").Replace(".ps1",".xml");
# 詳細ログを出力する場合には、Continueを指定
$VerbosePreference = "SilentlyContinue"
# Pesterの設定値を指定
$PesterPreference = [PesterConfiguration]::Default
$PesterPreference.Output.Verbosity = 'Detailed'
# Invoke-Pesterでテストコードを実行した上で、実行結果をJUnit形式に変換し、ファイル出力
Invoke-Pester $TargetCode -PassThru | ConvertTo-JUnitReport -AsString |Out-File $Result
9. (v) テスト
テストは、Division.Test-Exec.ps1 を実行する。
実行結果は、コンソール出力と同時にtest-resultフォルダにxmlで出力される
テスト実行結果(Console)
Pester v5.3.3
Starting discovery in 1 files.
Discovery found 4 tests in 19ms.
Running tests.
Running tests from '/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1'
Describing Function-001
Context 正常系
[+] [SampleFunction001]-N--[001] 16ms (5ms|11ms)
[+] [SampleFunction001]-N--[002] 18ms (9ms|9ms)
Context 異常
[+] [SampleFunction001]-AN-[001] 26ms (24ms|2ms)
[+] [SampleFunction001]-AN-[002] 42ms (22ms|20ms)
Tests completed in 228ms
Tests Passed: 4, Failed: 0, Skipped: 0 NotRun: 0
テスト実行結果-Division.Test-Exec.xml
<?xml version="1.0" encoding="utf-16" standalone="no"?>
<testsuites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="junit_schema_4.xsd" name="Pester" tests="4" errors="0" failures="0" disabled="0" time="0.228">
<testsuite name="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" tests="4" errors="0" failures="0" hostname="<machie-name>" id="0" skipped="0" disabled="0" package="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" time="0.228">
<properties>
<property name="machine-name" value="<machie-name>" />
<property name="user" value="tatt" />
<property name="user-domain" value="" />
<property name="cwd" value="/Users/<username>/Documents/powershell/pester/test-exec" />
<property name="os-version" value="20.6.0" />
<property name="junit-version" value="4" />
<property name="platform" value="Darwin" />
<property name="clr-version" value="Unknown" />
</properties>
<testcase name="Function-001.正常系.[SampleFunction001]-N--[001]" status="Passed" classname="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" assertions="0" time="0.020" />
<testcase name="Function-001.正常系.[SampleFunction001]-N--[002]" status="Passed" classname="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" assertions="0" time="0.021" />
<testcase name="Function-001.異常.[SampleFunction001]-AN-[001]" status="Passed" classname="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" assertions="0" time="0.032" />
<testcase name="Function-001.異常.[SampleFunction001]-AN-[002]" status="Passed" classname="/Users/<username>/Documents/powershell/pester/test-src/Division.Test.ps1" assertions="0" time="0.063" />
</testsuite>
</testsuites>
10. まとめ
- pesterを使ってテストコードの作成からテスト実行までの流れを記載できた
- 今後、Describe内で利用できる関数やShouldで指定できる内容を記載したい
11. 参考リンク