1

This PowerShell function identifies files which do not contain a particular string:

function GetFilesLackingItem([string]$pattern)
{
    Get-ChildItem | ? { !( Select-String -pattern $pattern -path $_ ) }
}

I am attempting to write a Pester unit test by mocking Get-ChildItem and Select-String but ran into an issue. Here are two attempts that both fail in the same way. The first test uses Mock's parameterFilter to differentiate, whereas the second test adds logic to do this in the mockCommand itself.

Describe "Tests" {
    $fileList = "nameA", "nameB", "nameC", "nameD", "nameE" | % {
        [pscustomobject]@{ FullName = $_; }
    }
    $filter = '(B|D|E)$'
    Mock Get-ChildItem { return $fileList }

    It "reports files that did not return a match" {
        Mock Select-String { "matches found" }  -param { $Path -match $filter }
        Mock Select-String 

        $result = Get-ChildItem | ? { !(Select-String -pattern "any" -path $_) }

        $result[0].FullName | Should Be "nameA"
        $result[1].FullName | Should Be "nameC"
        $result.Count | Should Be 2
    }

    It "reports files that did not return a match" {
        Mock Select-String {
            if ($Path -match $filter) { "matches found" } else { "" }
            }

        $result = Get-ChildItem | ? { !(Select-String -pattern "any" -path $_ ) }

        $result[0].FullName | Should Be "nameA"
        $result[1].FullName | Should Be "nameC"
        $result.Count | Should Be 2
    }
}

If I modify the tests such that the Select-String -path parameter is $_.FullName instead of $_ then both tests pass. But in real life (i.e. if I run the line without mocks) it works correctly with just $_. (It also works correctly with $_.FullName.) So the real Select-String seems able to map FullName from an array of FileInfo objects for the Path parameter (though I could not find that there was a parameter alias to do that).

My question: is it possible to leave the original code as is, i.e. leave the Path parameter as $_ on the line under test, and modify the Select-String mock instead to extract the FullName property? Trying for example, $Path.FullName in either mock does not work.

Michael Sorens
  • 35,361
  • 26
  • 116
  • 172
  • Does `Select-String` actually map `PSPath` property to `LiteralPath` parameter (alias `PSPath`, takes from pipeline by property name), not `FullName`? Can you try `PSPath` to `LiteralPath` instead of `FullName`? – Roman Kuzmin Aug 02 '14 at 06:04
  • @Roman: Not quite sure what you are suggesting. I have tried different combinations of properties in the $fileList instead of FullName, and also tried -LiteralPath vs -Path to Select-String, but have not found a combination that works. – Michael Sorens Aug 08 '14 at 02:18
  • I am not suggesting something specific. I just think that "Select-String seems able to map FullName from an array of FileInfo" is not quite correct because LiteralPath or PSPath is mapped, not FullName. – Roman Kuzmin Aug 08 '14 at 05:00

1 Answers1

1

since you are testing against a filesystem, i would suggest that instead of mocking the Get-ChildItem command you use the TestDrive to fake a filesystem for these kinds of tests.

See http://www.powershellmagazine.com/2014/09/30/pester-mock-and-testdrive/ for more details on using Testdrive:\.

oɔɯǝɹ
  • 7,219
  • 7
  • 58
  • 69