模拟命令并根据模拟调用的次数获得不同的结果

时间:2015-08-08 12:22:00

标签: unit-testing powershell pester

我正在使用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时,我想返回$false,第二次通话时我想返回$true。我可以想到几种实现这一目标的方法,但他们感觉不对:

  1. 在第一次通话时使用Path参数,第二次使用LiteralPath。有两个模拟,每个模拟一个ParameterFilter。我不喜欢黑客攻击代码的想法,以便进行测试。

  2. 使用以下参数创建一个函数:PathInstanceNumber。为函数创建模拟。这比上面的要好,但是我不喜欢将参数用于测试目的。

  3. 我看过,根据第n个电话找不到模拟方法。 Pester是否对此有所帮助,而我却错过了它?如果没有更清洁的方式来实现我想要的东西?

2 个答案:

答案 0 :(得分:4)

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' }


        }
}

我想你是在追求这个?!如果没有,请告诉我!

答案 1 :(得分:0)

问题可能在于您如何编写函数而使测试变得笨拙,因为函数可能变得相同...

相反,您应该从主要功能中提取功能,以便您可以分别测试它们。我不知道您的代码,但这只是我的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
    }
}