模拟命令并根据调用 Mock 的次数获得不同的结果
Mocking a command and getting different results based on the number of times the Mock is called
我正在使用 Pester 对我编写的一些代码进行单元测试。在测试中,我使用参数过滤器模拟 Test-Path
:
Mock -CommandName 'Test-Path' -MockWith { return $false } `
-ParameterFilter { $LiteralPath -and $LiteralPath -eq 'c:\dummy.txt' }
以下是我正在做的伪代码:
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "Exists"
}
else
{
Attempt to get file
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "File obtained"
}
}
第一次调用 Test-Path
我想 return $false
,第二次调用 return $true
。我可以想到几种实现此目的的方法,但感觉不对:
第一次调用使用 Path
参数,第二次使用 LiteralPath
。有两个模拟,每个模拟一个 ParameterFilter
。我不喜欢破解代码以方便测试的想法。
创建一个带有参数的函数:Path
和 InstanceNumber
。为函数创建模拟。这比上面的要好,但我不喜欢仅出于测试目的而使用参数的想法。
我已经看过,但找不到基于第 n 次调用的模拟方法。 Pester 是否促进了这一点,而我刚刚错过了它?如果没有,是否有更简洁的方法来实现我想要的?
function Test-File{
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "Exists"
}
else
{
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "File obtained"
}
}
}
Describe "testing files" {
it "file existence test" {
#Arrange
$script:mockCalled = 0
$mockTestPath = {
$script:mockCalled++
if($script:mockCalled -eq 1)
{
return $false
}
else
{
return $true
}
}
Mock -CommandName Test-Path -MockWith $mockTestPath
#Act
$callResult = Test-File
#Assert
$script:mockCalled | Should Be 2
$callResult | Should Be "File obtained"
Assert-MockCalled Test-Path -Times $script:mockCalled -ParameterFilter { $LiteralPath -and $LiteralPath -eq 'c:\dummy.txt' }
}
}
我想你是在追求这个?!如果没有请告诉我!
问题可能在于您编写函数的方式使得测试变得笨拙,因为函数可能变得相同...
相反,您应该从主函数中抽象出功能,这样您就可以单独测试它们。我不知道你的代码,但这只是我的 2 美分...
function MyFunction {
param (
$Path
)
$exists = (TestPathFirstCall $Path) -eq $true
if (-not $exists) {
$exists = (TryToCreateTheFile $Path) -eq $true
}
return $exists
}
function TestPathFirstCall {
param (
[string] $Path
)
Test-Path $Path
}
function TryToCreateTheFile {
param (
[string] $Path
)
New-Item $Path
Test-Path $Path
}
Describe 'Test-Path Tests' {
It 'Tries Test-Path twice, fails first time and returns true' {
Mock TestPathFirstCall {
return $false
}
Mock TryToCreateTheFile {
return $true
}
MyFunction "C:\dummy.txt" | Should BeExactly $true
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 1
}
It 'Tries Test-Path once and succeeds' {
Mock TestPathFirstCall {
return $true
}
Mock TryToCreateTheFile {
return $true
}
MyFunction "C:\dummy.txt" | Should BeExactly $true
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 0
}
It 'Tries Test-Path twice and fails' {
Mock TestPathFirstCall {
return $false
}
Mock TryToCreateTheFile {
return $false
}
MyFunction "C:\dummy.txt" | Should BeExactly $false
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 1
}
}
我正在使用 Pester 对我编写的一些代码进行单元测试。在测试中,我使用参数过滤器模拟 Test-Path
:
Mock -CommandName 'Test-Path' -MockWith { return $false } `
-ParameterFilter { $LiteralPath -and $LiteralPath -eq 'c:\dummy.txt' }
以下是我正在做的伪代码:
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "Exists"
}
else
{
Attempt to get file
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "File obtained"
}
}
第一次调用 Test-Path
我想 return $false
,第二次调用 return $true
。我可以想到几种实现此目的的方法,但感觉不对:
第一次调用使用
Path
参数,第二次使用LiteralPath
。有两个模拟,每个模拟一个ParameterFilter
。我不喜欢破解代码以方便测试的想法。创建一个带有参数的函数:
Path
和InstanceNumber
。为函数创建模拟。这比上面的要好,但我不喜欢仅出于测试目的而使用参数的想法。
我已经看过,但找不到基于第 n 次调用的模拟方法。 Pester 是否促进了这一点,而我刚刚错过了它?如果没有,是否有更简洁的方法来实现我想要的?
function Test-File{
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "Exists"
}
else
{
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "File obtained"
}
}
}
Describe "testing files" {
it "file existence test" {
#Arrange
$script:mockCalled = 0
$mockTestPath = {
$script:mockCalled++
if($script:mockCalled -eq 1)
{
return $false
}
else
{
return $true
}
}
Mock -CommandName Test-Path -MockWith $mockTestPath
#Act
$callResult = Test-File
#Assert
$script:mockCalled | Should Be 2
$callResult | Should Be "File obtained"
Assert-MockCalled Test-Path -Times $script:mockCalled -ParameterFilter { $LiteralPath -and $LiteralPath -eq 'c:\dummy.txt' }
}
}
我想你是在追求这个?!如果没有请告诉我!
问题可能在于您编写函数的方式使得测试变得笨拙,因为函数可能变得相同...
相反,您应该从主函数中抽象出功能,这样您就可以单独测试它们。我不知道你的代码,但这只是我的 2 美分...
function MyFunction {
param (
$Path
)
$exists = (TestPathFirstCall $Path) -eq $true
if (-not $exists) {
$exists = (TryToCreateTheFile $Path) -eq $true
}
return $exists
}
function TestPathFirstCall {
param (
[string] $Path
)
Test-Path $Path
}
function TryToCreateTheFile {
param (
[string] $Path
)
New-Item $Path
Test-Path $Path
}
Describe 'Test-Path Tests' {
It 'Tries Test-Path twice, fails first time and returns true' {
Mock TestPathFirstCall {
return $false
}
Mock TryToCreateTheFile {
return $true
}
MyFunction "C:\dummy.txt" | Should BeExactly $true
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 1
}
It 'Tries Test-Path once and succeeds' {
Mock TestPathFirstCall {
return $true
}
Mock TryToCreateTheFile {
return $true
}
MyFunction "C:\dummy.txt" | Should BeExactly $true
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 0
}
It 'Tries Test-Path twice and fails' {
Mock TestPathFirstCall {
return $false
}
Mock TryToCreateTheFile {
return $false
}
MyFunction "C:\dummy.txt" | Should BeExactly $false
Assert-MockCalled -Exactly TestPathFirstCall -Scope It -Times 1
Assert-MockCalled -Exactly TryToCreateTheFile -Scope It -Times 1
}
}