The Should Command and Core Operators
- powershell
- pester
- testing
- assertions
- should
Should is where a test earns its keep. Everything before it—Describe, It, loading your function—is scaffolding. Should is the moment you say what you believe is true. Master five operators and you can write 80% of the assertions you'll ever need.
What you'll learn
- The
Actual | Should -Operator Expectedshape every assertion follows -Beversus-BeExactlyand why case sensitivity matters- Checking for "nothing" with
-BeNullOrEmpty - Asserting booleans with
-BeTrueand-BeFalse - Checking a value's type with
-BeOfType - How to read a failure message so you can fix it fast
The shape of an assertion
Every Pester assertion reads left to right: you pipe the actual value into Should, name an operator, and supply the expected value.
'hello' | Should -Be 'hello'The thing on the left is what your code produced. The operator is the comparison. The thing on the right is what you expected. If they disagree, the test fails and Pester prints both. Keep that mental model and every operator below is just a variation on it.
-Be: everyday equality
-Be is the operator you'll reach for most. It compares two values for equality and, importantly, it is case-insensitive for strings.
Describe 'Core operators' {
It 'compares values with -Be' {
(2 + 2) | Should -Be 4
'PowerShell' | Should -Be 'powershell' # passes: case-insensitive
}
}That second line surprises people. -Be treats 'PowerShell' and 'powershell' as equal. When case matters, you need the next operator.
-BeExactly: equality that respects case
-BeExactly is -Be with case sensitivity turned on. Use it when the difference between Error and error is meaningful—status codes, tokens, generated identifiers.
It 'respects case with -BeExactly' {
'PowerShell' | Should -BeExactly 'PowerShell' # passes
# 'PowerShell' | Should -BeExactly 'powershell' # would FAIL
}Rule of thumb: default to -Be; switch to -BeExactly only when you can articulate why case matters.
-BeNullOrEmpty: checking for "nothing"
PowerShell has several flavors of "nothing": $null, an empty string '', and an empty array @(). -BeNullOrEmpty covers all of them in one assertion.
It 'detects empty values' {
$null | Should -BeNullOrEmpty
'' | Should -BeNullOrEmpty
@() | Should -BeNullOrEmpty
}This is handy for asserting that an optional result wasn't populated, or that a cleanup step really cleared a variable.
-BeTrue and -BeFalse: asserting booleans
When the value you're checking is genuinely a boolean, say so directly:
It 'asserts boolean results' {
(5 -gt 3) | Should -BeTrue
(Test-Path 'C:\nope-xyz') | Should -BeFalse
}-BeTrue and -BeFalse make the intent obvious at a glance—much clearer than $result | Should -Be $true. Reserve them for actual booleans; see Common mistakes for why.
-BeOfType: checking the type
Sometimes the value matters less than its type. -BeOfType takes a type literal (the [bracketed] form):
It 'checks the type of a value' {
'hello' | Should -BeOfType [string]
42 | Should -BeOfType [int]
(Get-Date) | Should -BeOfType [datetime]
}You can also pass the type name as a string—Should -BeOfType 'System.String'—but the [string] literal reads cleaner and is the common style.
Reading the failure message
Make a test fail on purpose so you recognize the output later:
Describe 'A failing assertion' {
It 'shows Expected vs Actual' {
'cat' | Should -Be 'dog'
}
}Pester reports something like:
Expected 'dog', but got 'cat'.That two-line "Expected / but got" pattern is the heart of every Pester failure. When a test goes red, read those two lines first: the left is what you asked for, the right is what the code actually did. Nine times out of ten that tells you whether the bug is in the code or in the test.
Try it yourself
Write one It block with three assertions about a single string value:
Describe 'My string' {
It 'is the expected value, present, and a string' {
$name = 'Ada'
$name | Should -Be 'Ada'
$name | Should -Not -BeNullOrEmpty
$name | Should -BeOfType [string]
}
}Run it, confirm it's green, then change 'Ada' to 'ada' in the function and watch which assertion stays green (hint: -Be won't complain). Swap that line to -BeExactly and see it go red.
Common mistakes
- Using
-Beon floating-point numbers.0.1 + 0.2 | Should -Be 0.3can fail because of binary rounding. For decimals, compare within a tolerance using-BeGreaterThan/-BeLessThan(Part 6) or round first:[math]::Round(0.1 + 0.2, 2) | Should -Be 0.3. - Reaching for
-eqout of habit.$x -eq 5evaluates before it reachesShould, so Pester only ever sees$trueor$false—you lose the helpful "Expected 5, but got 4" message. Always let the operator do the comparing:$x | Should -Be 5. - Asserting truthiness of a non-boolean.
'false' | Should -BeTruepasses, because a non-empty string is truthy in PowerShell. If you mean "equals the string false," use-Be 'false'. Save-BeTrue/-BeFalsefor real booleans.
Recap
Should follows one shape—Actual | Should -Operator Expected. -Be handles case-insensitive equality, -BeExactly adds case sensitivity, -BeNullOrEmpty catches the empty cases, -BeTrue/-BeFalse assert real booleans, and -BeOfType checks the type. Read the "Expected / but got" lines on any failure and you'll know where to look. Avoid -Be on floats and don't let -eq swallow your comparison.
Next up: Part 6 — Comparing Numbers, Strings, and Collections, where equality gives way to "greater than," "matches," and "contains."