6

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.

2
  • 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.. Commented Jan 30, 2018 at 4: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. Commented Jan 30, 2018 at 4:11

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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.
2

If you, for some reason

  • want to keep all functionality in a single script (as opposed to in a module or split into multiple files)
  • need the functionality to be executed when the script is dot sourced
  • want to test the script's functionality using Pester
  • don't mind adding some testability enhancing logic to the script

one approach is to add logic that skips auto-executing the script's functionality when a switch parameter is supplied.

I use something like that to keep my Azure Automation runbooks simple (simplicity is debatable; here "simple" translates to "keeping all functionality in a single script file") and testable:

SingleScript.Tests.ps1

BeforeAll { . $PSScriptRoot/SingleScript.ps1 -InTestContext } Describe 'SingleScript' { Context 'Invoke-Functionality' { It 'invokes script functionality' { $result = Invoke-Functionality $result | Should -Be 'Something useful' } } } 

In the test file above, within the BeforeAll block, auto-execution when dot sourcing is skipped with the switch parameter InTestContext.

SingleScript.ps1

param( [switch] $InTestContext ) function Invoke-Functionality { 'Something useful' } if (-not $InTestContext) { Invoke-Functionality } 

In the script file above, you can see the logic that allows skipping auto-execution.

Comments

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 } 

2 Comments

This seems very useful but how are you importing this into the Pester file to avoid the entire script running?
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).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.