Here's some pseudo-code showing the function to test:
function Set-Something
{
if (Test-Something)
{
return $True
}
# Not found so do something to create it.
Do-Something
# Check it's been created successfully.
if (Test-Something)
{
return $True
}
return $False
}
This must be a fairly common pattern: "Test for existence - if not found create - test again to verify creation". Testing most branches is pretty simple but how can I test the branch where Test-Something fails the first time it's called, then succeeds the second time it's called?
This is my test code so far:
Describe 'Set-Something' {
Context 'already exists' {
Mock Test-Something { return $True }
Mock Do-Something
It 'returns True' {
{ Set-Something } | Should -Be $True
}
It 'does not call Do-Something' {
Set-Something
Assert-MockCalled Do-Something -Times 0 -Exactly
}
}
Context 'does not already exist and creation fails' {
Mock Test-Something { return $False }
Mock Do-Something
It 'calls Do-Something' {
Set-Something
Assert-MockCalled Do-Something -Times 1 -Exactly
}
It 'calls Test-Something twice' {
Set-Something
Assert-MockCalled Test-Something -Times 2 -Exactly
}
It 'returns False' {
{ Set-Something } | Should -Be $False
}
}
Context 'does not already exist and creation succeeds' {
Mock Test-Something { ?? }
Mock Do-Something
It 'calls Do-Something' {
Set-Something
Assert-MockCalled Do-Something -Times 1 -Exactly
}
It 'calls Test-Something twice' {
Set-Something
Assert-MockCalled Test-Something -Times 2 -Exactly
}
It 'returns True' {
{ Set-Something } | Should -Be $True
}
}
}
The case 'does not already exist and creation succeeds' is the problem. Test-Something needs to be mocked so it fails the first time it's called, and succeeds the second time. The arguments passed to Test-Something will be identical in each call so I can't use ParameterFilter to create two mocks of Test-Something with different behaviour.