Reputation: 3344
I'm using Pester to unit test some code I've written. In the tests I mock Test-Path
using a parameter filter:
Mock -CommandName 'Test-Path' -MockWith { return $false } `
-ParameterFilter { $LiteralPath -and $LiteralPath -eq 'c:\dummy.txt' }
The following is psuedo code for what I'm doing:
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "Exists"
}
else
{
Attempt to get file
If ( Test-Path -LiteralPath c:\dummy.txt )
{
return "File obtained"
}
}
On the first call to Test-Path
I want to return $false
and on the second call I want to return $true
. I can think of a couple of ways of achieving this, but they don't feel right:
On the first call use the Path
parameter and on the second use LiteralPath
. Have two mocks one with a ParameterFilter
for each. I don't like the idea of hacking the code in order to facilitate a test.
Create a function with parameters for: Path
and InstanceNumber
. Create mocks for the function. This is better than the above, but I don't like the idea of having a parameter just for testing purposes.
I've looked and can't find a way to mock based on the nth call. Does Pester facilitate this and I've just missed it? If not is there a cleaner way of achieving what I want?
Upvotes: 2
Views: 2490
Reputation: 647
The problem probably lies in how you are writing your functions is making the testing unwieldy as the functions are probably becoming the same...
Instead you should abstract functionality out of your main function which allows you to test them individually. I don't know your code but this is just my 2 cents...
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
}
}
Upvotes: 0
Reputation: 1625
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' }
}
}
I think you are after this?! let me know if not!
Upvotes: 5