I am an utter newbie regarding PowerShell and am now tasked to write unit tests for some existing PowerShell scripts. It is a great task for me to learn about automating unit tests but have no idea where to begin. I followed several trainings about Pester and how to create unit tests with it and so far so good. Now comes the point to actually write a good test while using mocks and it is killing me. Even for a simple function that checks if a certain process is running and if it is killing it.
The function is as follows:
function Close-RunningApplications()
{
# Stop Task Manager, servcies.msc, Event Viewer, sysinternal ProcessExplorer etc. - sometimes keeps services from being delete correctly
$Process = Get-Process Taskmgr -ErrorAction SilentlyContinue
if($Process)
{
Write-Host "==| PreReq:: Close Task Manager" -foregroundcolor DarkCyan
taskkill /F /IM Taskmgr.exe
}
$Process = Get-Process mmc -ErrorAction SilentlyContinue
if($Process)
{
Write-Host "==| PreReq:: Microsoft Management Console" -foregroundcolor DarkCyan
taskkill /F /IM mmc.exe
}
$Process = Get-Process procexp64 -ErrorAction SilentlyContinue
if($Process)
{
Write-Host "==| PreReq:: Sysinternals Process Explorer" -foregroundcolor DarkCyan
taskkill /F /IM procexp64.exe
}
}
Close-RunningApplications | Write-Verbose -Verbose
Now I have written some tests for this to see some mocking functionality and I was surprised that all tests passed. It was only later that I realized that my tests actually run the tested script as well (running the tests with TaskManager open will actually close it)
# Get current working directory and set up script under test
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
# Include the script to test to make the defined functions available to the tests
. "$here\$sut"
$CommandName = $sut.replace(".ps1",'')
Describe "Tests for the $CommandName Function" {
It "Command $CommandName exists" {
Get-Command $CommandName -ErrorAction SilentlyContinue | Should Not Be NullOrEmpty
}
BeforeAll { Mock -CommandName 'Close-RunningApplications' {return 1}
Mock taskkill {return 2}
Mock Get-Process {$Process}
}
Context "Mocks Taskmanager" {
$Process = "Taskmgr"
$result = Get-Process
It "Mocks opening and closing Taskmanager" {
$result | Should Be "$Process"
taskkill | Should Be 2
Close-RunningApplications | Should Be 1
}
It "Asserts called mocks Get-Process"{
Assert-MockCalled 'Get-Process' -Exactly 1
}
It "Asserts called mocks Close-RunningApplications"{
Assert-MockCalled 'Close-RunningApplications' -Exactly 1
}
It "Asserts called mocks taskkill"{
Assert-MockCalled 'taskkill' -Exactly 1
}
}
Context "Mocks Microsoft Management Console" {
$Process = "mmc"
$result = Get-Process
It "Mocks opening and closing Microsoft Management Console" {
$result | Should Be "$Process"
taskkill | Should Be 2
Close-RunningApplications | Should Be 1
}
It "Asserts called mocks Get-Process"{
Assert-MockCalled 'Get-Process' -Exactly 1
}
It "Asserts called mocks Close-RunningApplications"{
Assert-MockCalled 'Close-RunningApplications' -Exactly 1
}
It "Asserts called mocks taskkill"{
Assert-MockCalled 'taskkill' -Exactly 1
}
}
Context "Mocks Sysinternals Process Explorer" {
$Process = "procexp64"
$result = Get-Process
It "Mocks opening and closing Sysinternals Process Explorer" {
$result | Should Be "$Process"
taskkill | Should Be 2
Close-RunningApplications | Should Be 1
}
It "Asserts called mocks Get-Process"{
Assert-MockCalled 'Get-Process' -Exactly 1
}
It "Asserts called mocks Close-RunningApplications"{
Assert-MockCalled 'Close-RunningApplications' -Exactly 1
}
It "Asserts called mocks taskkill"{
Assert-MockCalled 'taskkill' -Exactly 1
}
}
It "Asserts the totall mocks Get-Process" {
Assert-MockCalled 'Get-Process' -Exactly 3
}
It "Asserts the totall mocks Close-RunningApplications"{
Assert-MockCalled 'Close-RunningApplications' -Exactly 3
}
It "Asserts the totall mocks taskkill"{
Assert-MockCalled 'taskkill' -Exactly 3
}
}
I am a bit at a loss as to mocking..