pester / Pester

Pester is the ubiquitous test and mock framework for PowerShell.
https://pester.dev/
Other
3.08k stars 470 forks source link

Pester shoud understand arrays #246

Closed vors closed 7 years ago

vors commented 9 years ago

This test fails on a4244c3c3825f4a108be5283a98bb6eb7a3e3508 (v4 branch)

Describe "Pester shoud understand arrays" {
    It "two arrays are different" {
        @(1) | Should not be @(1,2)
    }
}
vors commented 9 years ago

Same on eaf270ab3f7620fe47e5470ca14afab25a8c5a9b (master)

vors commented 9 years ago

It's a pipeline, this works fine

Describe "Pester shoud understand arrays" {
    It "two arrays are different" {
        @(, @(1)) | Should not be @(, @(1,2))
    }
}
vors commented 9 years ago

I'm still not satisfied:

Describe "Pester shoud understand arrays" {
    It "Arrays should be the same" {
        @(, @(1, 2)) | Should be @(, @(1, 2))
    }
}

image

dlwyatt commented 9 years ago

I started looking into this several months ago, but ran into some annoying headaches and threw out the code. Here's what I remember about it:

Once those design questions are sorted out, the coding itself isn't too hard. The only thing that we can't solve without a breaking change would be the quirks related to using a pipeline, and those can be solved by the caller if they simply use a unary comma (or Write-Output -NoEnumerate) before piping to Should. For example:

,$array1 | Should Be $array2

Another option would be to make a command that doesn't involve the pipe, something like

Assert $array1 Should Be $array2
vors commented 9 years ago

I forgot that PowerShell treat -eq as filter operation for arrays

@('x') -eq @('x')
x
dlwyatt commented 9 years ago

I suppose we can start with a fairly simple approach:

Sound like a plan? If so, I basically already did that work (and I may still have that old branch lying around somewhere.) The only annoying quirk that I can remember was this:

$null | Should Be @()
@() | Should Be $null

Both of those tests would succeed, because there was no way for the method to know whether the original input was an empty array or $null. However, that's an edge case that's not really that big of a deal (other than annoying me.)

This is something we can include in v4. It's technically a breaking change, though it's probably unlikely that anyone is depending on the old behavior of -eq and collections.

vors commented 9 years ago

That sounds perfect for me.

francoislg commented 9 years ago

I hit the same wall with arrays today and I think it's a wonderful idea to support it.

I've come up with a simple solution that works quite well for my context (thought probably not elegant enough) to compare two arrays regardless of their order.

function Assert-ArrayEquals { param($array, $expected) for($i = 0; $i -lt $expected.length; $i++){ $expected -contains $array[$i] | Should Be $true } }

The only problem is that it isn't quite verbose enough (Only return "expected : true but was false") but I think it's solvable without affecting performance.

Hope that helps others !

FOLLOW-UP : I ended up adding "MatchArray" in the assertions which does exactly the same as my code above. And now this works :

@("1","2") | Should MatchArray @("2","1")

And it wouldn't be hard to do a MatchArrayWithOrder or something like that.

it-praktyk commented 8 years ago

Please check @stuartleeks projects

More Pester's related links on my blog -> https://blog.it-praktyk.pl/2016/05/29/Pester-related-links/

DarkLite1 commented 7 years ago

Stumbled upon this too and tried to use the suggested solution with PesterMatchArray, but it doesn't test the content deeply enough . So in the end I reverted to this post and used the following test:

$Result = @(
    [PSCustomObject]@{
        'First Name' = 'Chuck'
        'Address'    = 'California'
    }
    [PSCustomObject]@{
        'First Name' = 'Jean-Claude'
        'Address'    = 'Brussels'
    }
)

$ExpectedResult = @"
[
    {
        "First Name":  "Chuck",
        "Address":  "California"
    },
    {
        "First Name":  "Jean-Claude",
        "Address":  "Brussels"
    }
]
"@

[String]::Compare(($Result | ConvertTo-Json),$ExpectedResult) | Should Be 0
nohwnd commented 7 years ago

Maybe this could help you: https://github.com/nohwnd/Assert#comparing-whole-objects

DarkLite1 commented 7 years ago

Perfect! Even better! Thank you very much for the helpful module. Love it already! Only thing missing is case sensitivity, but that's just nitpicking.

it-praktyk commented 7 years ago

I assume that the issue can be closed soon (7 days). Feel free to send any additional information that can be helpful to answer your question/issue.

PatrickGrub commented 6 years ago

Would be nice if Pester itself provides such a functionality without installing other modules like the mentioned one from @stuartleeks

I would love that!

Thanks, Patrick

jrobiii commented 6 years ago

Not a solution, but a workaround. The way that I'm working around this issue is by gathering the results into a variable and then doing multiple Should(s). Like so: It 'GetCsvKvp returns correct KVP array from a CsvString with correctly formatted CSV and valid KVP (key value pair)' { $KvpArray = GetCsvKvp -CsvString 'this=that,those=them' $KvpArray | Should -HaveCount 2 ($KvpArray | where {$_.Name -eq 'this'} ).Value | Should -Be 'that' ($KvpArray | where {$_.Name -eq 'those'} ).Value | Should -Be 'them' }

Works great for small scenarios. Hope this helps someone.

Jim Roberts

DannyArr commented 6 years ago

I just hit this as well. I tried the below, worked for me. I created a little helper function to re-order the array if the contents matched.

function Convert-ArrayOrderToSource {
    param (
        [parameter(mandatory=$true)]
        [array]$SourceArray,

        [parameter(mandatory=$true)]
        [array]$DifferenceArray
    )

    if(!(Compare-Object -ReferenceObject $a -DifferenceObject $b)) {
        $result = $SourceArray
    }
    else {
        $result = $DifferenceArray
    }
    return $result
}

Then in my pester test I convert the array. If it doesn't match it just spits out the original array and will fail the test.

$propertiesInOrder | Should -Be $expectedProperties