5

I am testing a PowerShell script. I'd like to test individual functions without executing the entire script. I am not sure if this is the intended use case or supported, and I am not finding a good answer searching online

sut.ps1:

Param(
    [Parameter(Mandatory = $true,
        Position = 0)]
    [ValidateNotNullOrEmpty()]
    [string] $Message
)

function fut([string] $argument) {
    Write-Host $argument
}

function Main() {
    fut($Message)
}

Main

sut.tests.ps1:

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut" "Message"

Describe "fut" {
    It "does something useful" {
        fut 'beer'
    }
}

Output

Message
Describing fut
beer
 [+] does something useful 385ms
Tests completed in 385ms

Now I can mock away 'beer', because it runs in the describe block. But I cannot mock away 'message', because the script starts to execute when I dot-source it.

In my case, 'message' is an operation I do not want to execute.

I am on Windows 10 15063.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Martin K
  • 183
  • 9
  • 1
    You're not building your scripts in a way that is able to be tested. Furthermore, your functions shouldn't call each other in their definitions.. – Maximilian Burszley Jan 30 '18 at 04:09
  • 3
    Before dot-sourcing your script, try `set-alias main out-null`. It should suppress the call to `main`. After dot-sourcing, you may remove this alias. – Roman Kuzmin Jan 30 '18 at 04:11

2 Answers2

4

Per the comments, the issue is that your script is self-executing, so it's not possible to load it for Pester via dot-sourcing without also executing the functions.

The workaround suggested by Roman to temporarily use Set-Alias to set main to Out-Null would work. Another suggestion would be to separate your functions to a separate file (e.g named functions.ps1) and then in your original script you can use dot sourcing to include it, but in your test script just dot source the functions.ps1 file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark Wragg
  • 22,105
  • 7
  • 39
  • 68
  • Thanks. I have some shared code in a psm1 and I guess I will be separating business logic and front end in the future to make it easier to test code. – Martin K Jan 30 '18 at 17:59
0

This will only run the main function if it is not called ny Dot Source, as a pester script would. I am using this instead of splitting functions to another file where it is not needed. Then pester runs without invoking the Main function.

if (-not ($MyInvocation.InvocationName -eq "."))
{
    Main
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • This seems very useful but how are you importing this into the Pester file to avoid the entire script running? – gerard Apr 26 '22 at 12:28
  • I was able to get this working by using `$MyInvocation.InvocationName -match ".+.ps1"` so that the Main function will only trigger when started by calling a script, rather than importing the script from a different script (or Pester file). – gerard Apr 26 '22 at 13:52