在 .ps1 脚本中模拟函数
Mock a function within a .ps1 script
我有一个 PowerShell .ps1 文件,它在脚本顶部包含函数,后面是调用这些函数的不同命令。我正在使用 Pester 对我的脚本文件进行单元测试。
如何模拟 PowerShell .ps1 脚本中的函数?
我试过模拟函数,但我收到一条错误消息 "could not find command"。
我还尝试在 describe 块中添加一个空的 "dummy" 函数。这并没有给我上面的错误,但它没有正确模拟脚本中的函数。
我有两个文件。一个保存测试,另一个保存函数和对函数的调用。下面是两个例子:
文件 1.ps1
Function Backup-Directory([switch]$IsError)
{
If($IsError)
{
Write-Error "Error"
Exit 1
}
}
Backup-Directory $true
File2.Tests.ps1
$here = (Split-Path -Parent $MyInvocation.MyCommand.Path) -replace '\test', '\main'
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
$productionFile = "$here$sut"
Describe "File1" {
Context "When the Back-Directory outputs an error." {
# Arrange
Mock Back-Directory { }
Mock Write-Error
# Act
& $productionFile
$hasSucceeded = $?
# Assert
It "Calls Backup-Directory" {
Assert-MockCalled Backup-Directory -Exactly 1 -ParameterFilter {
$IsError -eq $true
}
}
It "Writes error message." {
Assert-MockCalled Write-Error -Exactly 1 -ParameterFilter {
$Message -eq "Error"
}
}
It "Exits with an error." {
$hasSucceeded | Should be $false
}
}
}
我认为这是不可能的。至少在您当前的实施中。我刚才问过同样的问题... Pester Issue 414
但是您可以将该内部函数拆分到同一目录中的另一个脚本文件中,从而允许您对其进行单元测试和模拟。您只需在主脚本文件中点源函数即可使用它:
主要功能。ps1:
# Main script
function Main-Function {
# if debugging, set moduleRoot to current directory
if ($MyInvocation.MyCommand.Path) {
$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
}else {
$moduleRoot = $PWD.Path
}
# dot source the inner function
. "$moduleRoot\Inner-Function.ps1"
Write-Output "This is the main script. Calling the inner function"
Inner-Function
Write-Output "Back in the main script"
}
内部函数。ps1:
function Inner-Function {
Write-Output "This is the inner function"
}
主要-Function.Tests.ps1:
$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# Load Testing Function
. "$moduleRoot\Main-Function.ps1"
# Load Supporting Functions
. "$moduleRoot\Inner-Function.ps1"
Describe 'Main Script' {
Mock Inner-Function { return "This is a mocked function" }
It 'uses the mocked function' {
(Main-Function -match "This is a mocked function") | Should Be $true
}
}
这是一个非常好的方法,因为我们可以对内部函数进行单元测试,并且随着逻辑的增长,向其添加测试非常容易(并且可以独立于 scripts/functions 的其余部分完成) .
内-Functions.Tests.ps1:
$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# Load Testing Function
. "$moduleRoot\Inner-Function.ps1"
Describe 'Inner Function' {
It 'outputs some text' {
Inner-Function | Should Be "This is the inner function"
}
}
这里有两个要点...
无论您当前的执行目录如何,都在查找依赖函数位置...
if ($MyInvocation.MyCommand.Path) {
$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
}else {
$moduleRoot = $PWD.Path
}
和
Dot Sourcing 取决于主函数中的函数以及单元测试文件.... "$moduleRoot\Inner-Function.ps1"
Split-Path -Path $MyInvocation.MyCommand.Path
在用户会话中是 $null
,但在执行上下文中调用时不会是 $null
。意思是,您可以在 C:\users\nhudacin
中并仍然正确加载此 script/module。否则,您将不得不始终从与它所在的同一目录中执行此 script/module,而不使用 $MyInvoation
变量。
我有一个 PowerShell .ps1 文件,它在脚本顶部包含函数,后面是调用这些函数的不同命令。我正在使用 Pester 对我的脚本文件进行单元测试。
如何模拟 PowerShell .ps1 脚本中的函数?
我试过模拟函数,但我收到一条错误消息 "could not find command"。
我还尝试在 describe 块中添加一个空的 "dummy" 函数。这并没有给我上面的错误,但它没有正确模拟脚本中的函数。
我有两个文件。一个保存测试,另一个保存函数和对函数的调用。下面是两个例子:
文件 1.ps1
Function Backup-Directory([switch]$IsError)
{
If($IsError)
{
Write-Error "Error"
Exit 1
}
}
Backup-Directory $true
File2.Tests.ps1
$here = (Split-Path -Parent $MyInvocation.MyCommand.Path) -replace '\test', '\main'
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
$productionFile = "$here$sut"
Describe "File1" {
Context "When the Back-Directory outputs an error." {
# Arrange
Mock Back-Directory { }
Mock Write-Error
# Act
& $productionFile
$hasSucceeded = $?
# Assert
It "Calls Backup-Directory" {
Assert-MockCalled Backup-Directory -Exactly 1 -ParameterFilter {
$IsError -eq $true
}
}
It "Writes error message." {
Assert-MockCalled Write-Error -Exactly 1 -ParameterFilter {
$Message -eq "Error"
}
}
It "Exits with an error." {
$hasSucceeded | Should be $false
}
}
}
我认为这是不可能的。至少在您当前的实施中。我刚才问过同样的问题... Pester Issue 414
但是您可以将该内部函数拆分到同一目录中的另一个脚本文件中,从而允许您对其进行单元测试和模拟。您只需在主脚本文件中点源函数即可使用它:
主要功能。ps1:
# Main script
function Main-Function {
# if debugging, set moduleRoot to current directory
if ($MyInvocation.MyCommand.Path) {
$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
}else {
$moduleRoot = $PWD.Path
}
# dot source the inner function
. "$moduleRoot\Inner-Function.ps1"
Write-Output "This is the main script. Calling the inner function"
Inner-Function
Write-Output "Back in the main script"
}
内部函数。ps1:
function Inner-Function {
Write-Output "This is the inner function"
}
主要-Function.Tests.ps1:
$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# Load Testing Function
. "$moduleRoot\Main-Function.ps1"
# Load Supporting Functions
. "$moduleRoot\Inner-Function.ps1"
Describe 'Main Script' {
Mock Inner-Function { return "This is a mocked function" }
It 'uses the mocked function' {
(Main-Function -match "This is a mocked function") | Should Be $true
}
}
这是一个非常好的方法,因为我们可以对内部函数进行单元测试,并且随着逻辑的增长,向其添加测试非常容易(并且可以独立于 scripts/functions 的其余部分完成) .
内-Functions.Tests.ps1:
$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# Load Testing Function
. "$moduleRoot\Inner-Function.ps1"
Describe 'Inner Function' {
It 'outputs some text' {
Inner-Function | Should Be "This is the inner function"
}
}
这里有两个要点...
无论您当前的执行目录如何,都在查找依赖函数位置...
if ($MyInvocation.MyCommand.Path) {
$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
}else {
$moduleRoot = $PWD.Path
}
和
Dot Sourcing 取决于主函数中的函数以及单元测试文件.... "$moduleRoot\Inner-Function.ps1"
Split-Path -Path $MyInvocation.MyCommand.Path
在用户会话中是 $null
,但在执行上下文中调用时不会是 $null
。意思是,您可以在 C:\users\nhudacin
中并仍然正确加载此 script/module。否则,您将不得不始终从与它所在的同一目录中执行此 script/module,而不使用 $MyInvoation
变量。