04 / DEFENSIVE AUTOMATION AND REPORTING · LESSON 16

Test the boundary of a detection rule

Write Pester checks that catch a threshold bug instead of only proving that a test can pass.

18 min · learn at your pace

A passing suite needs useful assertions

The supplied Detection.ps1 defines Test-FailureThreshold. Its contract is simple: fewer than three failures returns false; three or more returns true. The boundary is exactly where -ge accidentally becoming -gt would change behaviour.

Write three named Pester tests for counts 2, 3, and 4. Put setup in BeforeAll and dot-source the supplied helper there. Each It block should call the function and assert the expected boolean, rather than assert a constant unrelated to the function.

BeforeAll { . '/home/user/Detection.ps1' }
Describe 'Example assertion' {
    It 'checks a boolean result' { (1 -lt 2) | Should -BeTrue }
}

Store and run the tests

Use a single-quoted here-string to write /home/user/Detection.Tests.ps1 from your editor. Start it with @' and finish with '@ on its own line. Then run Invoke-Pester with -PassThru -Output None to return the result object without its display output.

The course checker also temporarily substitutes deliberately broken helper implementations: always true, always false, and greater-than-three. Your test suite must reject each. This is a small form of mutation testing: it checks that the assertions can notice plausible mistakes. The original fixture is restored after each check.

Pester is already bundled in the lab; no package installation is needed.

Try an example.ps1
. '/home/user/Detection.ps1'
2..4 | ForEach-Object { [pscustomobject]@{ Count=$_; Flagged=(Test-FailureThreshold -Count $_) } }
YOUR TURN

Put it into practice.

Create Detection.Tests.ps1 containing exactly three unskipped Pester tests of Test-FailureThreshold: count 2 → false, 3 → true, and 4 → true. Load /home/user/Detection.ps1 inside BeforeAll. Run the suite with -PassThru -Output None and emit its result. Do not redefine or edit the supplied function. Your tests must fail for the deliberately broken implementations described above.

See an explained solution
One way to solve it.ps1
@'
BeforeAll { . '/home/user/Detection.ps1' }
Describe 'Failure threshold' {
    It 'does not flag two failures' { Test-FailureThreshold -Count 2 | Should -BeFalse }
    It 'flags exactly three failures' { Test-FailureThreshold -Count 3 | Should -BeTrue }
    It 'flags four failures' { Test-FailureThreshold -Count 4 | Should -BeTrue }
}
'@ | Set-Content '/home/user/Detection.Tests.ps1'
Invoke-Pester '/home/user/Detection.Tests.ps1' -PassThru -Output None

The suite exercises values below, at, and above the boundary. The mutation checks demonstrate that it depends on the real function and detects the specific off-by-one failure.