Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing of ForEach-Object -Parallel #2356

Open
3 tasks done
JanElholm opened this issue May 24, 2023 · 4 comments
Open
3 tasks done

Testing of ForEach-Object -Parallel #2356

JanElholm opened this issue May 24, 2023 · 4 comments

Comments

@JanElholm
Copy link

JanElholm commented May 24, 2023

Checklist

Summary of the feature request

$TimeToSleep = 5
1..10 | ForEach-Object -Parallel {
    $TimeToSleep = $using:TimeToSleep
    Start-Sleep $TimeToSleep
} -ThrottleLimit 5

I would like to be able to mock a function inside of a "ForEach-Object -Parallel". In the above rather contrieved example I would like to be able to mock the Start-Sleep function

Thx

How should it work?

No response

@fflaten
Copy link
Collaborator

fflaten commented May 24, 2023

Unfortunately that's not possible.

Using -Parallel runs the scriptblock-code in new PowerShell runspaces (threads). The new runspaces doesn't share any state like imported modules, variables etc. with your normal session. So the Pester-module and any knowledge of existing mocks are invisble inside.

@JanElholm
Copy link
Author

Sorry to hear that it's not possible. Any recommendation or best practises on how to implement multithreading in powershell in order to make it testable with Pester?

@fflaten
Copy link
Collaborator

fflaten commented May 26, 2023

It's mostly mocking objects and commands that won't work.

You can test the results of any code using multithreading, so maybe focus on integration tests against test-data/environments?

@DarkLite1
Copy link
Contributor

DarkLite1 commented Feb 22, 2024

Running into this same limitation of Pester. Some easy repro code:

Describe 'it should be' {
    BeforeAll {
        $realCmdLet = @{
            InvokeCommand = Get-Command Invoke-Command
        }

        Mock Invoke-Command {
            & $realCmdLet.InvokeCommand -Scriptblock {
                1
            } -ComputerName $env:COMPUTERNAME
        }

        $testData = @(
            @{ComputerName = 'PC1' }
            @{ComputerName = 'PC2' }
        )
    }
    It 'green' {
        $testData | ForEach-Object {
            Invoke-Command -ComputerName $_.ComputerName -ScriptBlock { 1 }
        }

        Should -Invoke Invoke-Command -Times 1 -Exactly -ParameterFilter {
            $ComputerName -eq 'PC1'
        }

        Should -Invoke Invoke-Command -Times 1 -Exactly -ParameterFilter {
            $ComputerName -eq 'PC2'
        }
    }
    It 'green' {
        $testData | ForEach-Object -Parallel {
            Invoke-Command -ComputerName $_.ComputerName -ScriptBlock { 1 }
        }

        Should -Invoke Invoke-Command -Times 1 -Exactly -ParameterFilter {
            $ComputerName -eq 'PC1'
        }

        Should -Invoke Invoke-Command -Times 1 -Exactly -ParameterFilter {
            $ComputerName -eq 'PC2'
        }
    }
}

The last test fails because of Foreach-Object -Parallel creating its own runspaces in which Pester can't utilise mocks.

@nohwnd @fflaten is there really no way around this?

It would maybe be an idea if Pester could remove the -Parallel switch and run it in the same thread just for debugging purposes. But that would also entail replacing variables that start with $using:xxx.

Related StackOverflow question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants