Pester
Pester copied to clipboard
Problem using HaveCount on [hashtable]
1. General summary of the issue
When using HaveCount
on a hashtable, the count is always 1. The following snippet shows the problem (both in Windows PowerShell and PowerShell Core).
Describe 'Get-HashTable' {
Context 'When returning a hashtable' {
It 'Test' {
$getHashTableResult = @{
Property1 = '1'
Property2 = '3'
}
$getHashTableResult | Should -BeOfType [System.Collections.Hashtable]
$getHashTableResult | Should -HaveCount 2
}
}
}
2. Describe Your Environment
Pester version : 5.1.1 C:\source\SqlServerDsc\output\RequiredModules\Pester\5.1.1\Pester.psm1
PowerShell version : 7.1.0
OS version : Microsoft Windows NT 10.0.19042.0
3. Expected Behavior
HaveCount
should report the correct number of properties in the hashtable.
4.Current Behavior
Fails with an error even though there are two properties in the hashtable.
Starting discovery in 1 files.
Discovery finished in 22ms.
[-] Get-HashTable.When returning a hashtable.Test 8ms (7ms|1ms)
Expected a collection with size 2, but got collection with size 1 @(System.Collections.Hashtable).
at $getHashTableResult | Should -HaveCount 2, C:\Users\johan.ljunggren\Desktop\Bug_HaveCount.ps1:10
5. Possible Solution
NOTE: The below screenshots are from Pester 4.x, but the same issue still exist in 5.1.1.
The problem seems that it compares the wrong array. Instead of checking $ActualValue.Count
, it should check $ActualValue[0].Count
(at least in this case).
[DBG]> $ActualValue.Count
1
[DBG]> $ActualValue[0].Count
2
6. Context
Very minor inconvenience. Having HaveCount
would just make the code prettier. Workaround is using the following instead.
$getHashTableResult.Count | Should -Be 2
I have updated the issue for the Pester 5.1.1 where the issue still exist. It is also not possible to use ActualValue
.
Describe 'Get-HashTable' {
Context 'When returning a hashtable' {
It 'Test' {
$getHashTableResult = @{
Property1 = '1'
Property2 = '3'
}
Should -ActualValue $getHashTableResult -HaveCount 2
}
}
}
It is not possible to use $getHashTableResult.Keys
either.
Describe 'Get-HashTable' {
Context 'When returning a hashtable' {
It 'Test' {
$getHashTableResult = @{
Property1 = '1'
Property2 = '3'
}
Should -ActualValue $getHashTableResult.Keys -HaveCount 2
}
}
}
Starting discovery in 1 files.
Discovery finished in 18ms.
[-] Get-HashTable.When returning a hashtable.Test 7ms (6ms|1ms)
Expected a collection with size 2, but got collection with size 1 @(@('Property1', 'Property2')).
at Should -ActualValue $getHashTableResult.Keys -HaveCount 2, C:\Users\johan.ljunggren\Desktop\Bug_HaveCount.ps1:9
You can use
$getHashTableResult.Keys | Should -HaveCount 2
or
$getHashTableResult.GetEnumerator() | Should -HaveCount 2
.
A hashtable is considered a single item when passed through the pipeline (and in a foreach-loop), so you would need $getHashTableResult.GetEnumerator()
to make it work. Keys
however can be looped through directly. We could add logic to work around it for dictionaries, but personally I'd recommend not to do that considering this is normal powershell behaviour and not a Pester-specific quirk. So it might be best to let Pester behave the same as a normal foreach-loop or Foreach-Object
will.
Should -ActualValue $getHashTableResult.Keys -HaveCount 2
doesn't currently work as Should doesn't loop $ActualValue
when using the parameter directly, only when provided through the pipeline. That's normally solved by adding a foreach($i in $ActualValue)
-loop in Should's process block, but it will break nested array sent through pipeline ++, so this limitation is probably by-design. @nohwnd ?
I good with closing this issue. If Should -ActualValue $getHashTableResult.Keys -HaveCount 2
should work then we can open up a separate issue for that. Let see what @nohwnd thinks.
Stumbled upon this issue with Pester 5.1.1:
Describe 'a hash table should be correctly counted with' {
BeforeAll {
$hashTable = @{
Key1 = 1
Key2 = 2
}
}
It '-BeExactly' {
$hashTable.Count | Should -BeExactly 2
}
It '-HaveCount' {
$hashTable | Should -HaveCount 2 # FAIL
}
}
Describe 'an array should be correctly counted with' {
BeforeAll {
$array = @(1, 3)
}
It '-BeExactly' {
$array.Count | Should -BeExactly 2
}
It '-HaveCount' {
$array | Should -HaveCount 2
}
}
It would be great if Pester would simply check the type and if it's a hasthtable check how many keys there are. @nohwnd , is this something that would be considered?
Having also stumbled over this recently too, I have to agree.
From a usability point of view, it's very confusing: You're testing an object that has a Count
property, but Should -HaveCount
doesn't work on it...?!
@iambic69 No disagreement here, but sometimes there are technical limitations. The problem is that due to the pipeline-behavior in PowerShell which doesn't enumerate hashtables-entries unlike other ICollection/IEnumerable
-types, then by fixing @{"one"=1,"two"=2} | Should -HaveCount 2
we would just as easily break arrays with a single dictionary-item
# Would fail due to count of 2 keys and not 1 hashtable as expected
@(@{"one"=1,"two"=2}) | Should -HaveCount 1
That is unless someone has an idea of how to properly detect "a single dictionary" vs "array with single dictionary" through the pipeline.