Reputation: 3351
I would like to define stand-alone functions in my PowerShell script and be able to Pester test the functions without executing the rest of the script. Is there any way to do this without defining the functions in a separate file?
In the following pseudocode example, how do I test functionA or functionB without executing mainFunctionality?
script.ps1:
functionA
functionB
...
mainFunctionality
script.Tests.ps1:
BeforeAll {
. $PSScriptRoot/script.ps1 # This will execute the mainFunctionality, which is what I want to avoid
}
Describe 'functionA' {
# ... tests
}
I believe in Python, you can do this by wrapping your "mainFunctionality" inside this condition, so I am looking for something similar in Powershell.
if __name__ == '__main__':
mainFunctionality
Ref: What does if __name__ == "__main__": do?
Upvotes: 3
Views: 1037
Reputation: 60668
You could use $MyInvocation.PSCommandPath
to determine who invoked your script, it's the closest I can think of to Python's if __name__ == '__main__':
.
This property will give you the absolute path of the caller, from there you can extract the script's name, i.e. with Path.GetFileName
and after you can determine what you want to do, for example, call mainFunctionality
if the caller's name equals to main.ps1
or call mainFunctionality
if the caller's name is not equal to script.Tests.ps1
, etc. Short demo below.
myScript.ps1
function A {
"I'm function A"
}
function B {
"I'm function B"
}
function mainFunctionality {
"I'm function mainFunctionality"
}
A # Calls A
B # Calls B
# Call `mainFunctionality` only if my caller's name is `main.ps1`
if([System.IO.Path]::GetFileName($MyInvocation.PSCommandPath) -eq 'main.ps1') {
mainFunctionality
}
Then if calling myScript.ps1
from main.ps1
you would see:
I'm function A
I'm function B
I'm function mainFunctionality
And if calling myScript.ps1
from anywhere else (console or other script with a different name) you would see:
I'm function A
I'm function B
Upvotes: 2
Reputation: 23788
Using the PowerShell Abstract Syntax Tree (AST) to just grab functionA
and invoke it:
$ScriptBlock = {
function functionA {
Write-Host 'Do something A'
}
function functionB {
Write-Host 'Do something A'
}
function mainFunctionality {
# Do something
functionA
# Do something
functionB
# Do something
}
mainFunctionality
}
Using NameSpace System.Management.Automation.Language
$Ast = [Parser]::ParseInput($ScriptBlock, [ref]$null, [ref]$null) # or: ParseFile
$FunctionA = $Ast.FindAll({
$Args[0] -is [ScriptBlockAst] -and $Args[0].Parent.Name -eq 'functionA'
}, $True)
Invoke-Expression $FunctionA.EndBlock
Do something A
Upvotes: 1