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

Allow Data driven test template parameters to be be passed into a Mock #2071

Closed
plastikfan opened this issue Sep 1, 2021 · 11 comments
Closed

Comments

@plastikfan
Copy link
Contributor

Summary of the feature request

Currently, when a suite of data driven tests is defined with the -TestCases option, the defined template parameters are not currently available to use inside a Mock. Here is an example:

Describe 'Initialize-ShellOperant' {
  BeforeAll {
    InModuleScope -ModuleName Elizium.Loopz {
      Get-Module Elizium.Loopz | Remove-Module -Force; ;
      Import-Module .\Output\Elizium.Loopz\Elizium.Loopz.psm1 `
        -ErrorAction 'stop' -DisableNameChecking -Force;
    }
    [string]$script:_HomePath = $(Join-Path -Path $TestDrive -ChildPath 'username');
    [string]$script:_EliziumPath = $(Join-Path -Path $_HomePath -ChildPath 'elizium');
  }

  Context 'given: <UndoRenameDisabled>, <EliziumPath>' {
    It 'should: ' -Tag 'Current' -TestCases @(
      , @{ UndoRenameDisabled = $false; EliziumPath = $_EliziumPath; }
    ) {
      Mock -ModuleName Elizium.Loopz Get-EnvironmentVariable {
        param(
          [Parameter()]
          [string]$Variable
        )
        $result = switch ($Variable) {
          'LOOPZ_UNDO_RENAME' {
            $UndoRenameDisabled;
            break;
          }

          'ELIZIUM_PATH' {
            $EliziumPath;
            break;
          }

          'HOME' {
            $HomePath;
            break;
          }
        }

        return $result;
      }
    }
  }

So we have 2 template variables UndoRenameDisabled and EliziumPath. These variables are accessible from the test code directly inside the It block. However, they are not bound inside the Get-EnvironmentVariable Mock. So in this example, $UndoRenameDisabled and $EliziumPath referenced inside the switch statement are not bound in.

The only way to get aound this issue is to artifically run inside module scope, because the InModuleScope function has a Parameters param. It would be great if there was a Parameters param on Mock in the same way, so we don't have to run InModuleScope just so we can access template parameters.

How should it work? (optional)

Should be implemented in the same way as #1957

@nohwnd
Copy link
Member

nohwnd commented Sep 1, 2021

The body you provide to mock will be invoked in the scope where it was defined, in this case in the test. The variables from -Foreach / -TestCases are defined in test as well. You should be able to use them without doing anything special. In fact using InModuleScope around the Mock would prevent you from getting the variables, because the body of the mock would run in the module, not in the test.

BeforeDiscovery {
    Get-Module a | Remove-Module
    New-Module a -ScriptBlock {
        function p () { g }
        function g () { Write-Host "real g" }

        Export-ModuleMember -Function p
    } | Import-Module
}
Describe "a" {
    It "b" -Foreach @{Hello = "heya!" } {
        function f () { Write-Host "real f" }
        Mock f {
            Write-Host "Greeting: $hello"
        }

        Mock g {
            Write-Host "Greeting2: $hello"
        } -ModuleName a

        f # mock is effective directly in test, body runs in test
        p # mock is effective in module a, body still runs in test
    }
}
Starting discovery in 1 files.
Discovery found 1 tests in 26ms.
Running tests.
Greeting: heya!
Greeting2: heya!
[+] C:\Users\jajares\Desktop\hl.tests.ps1 104ms (43ms|37ms)
Tests completed in 105ms
Tests Passed: 1, Failed: 0, Skipped: 0 NotRun: 0

@fflaten
Copy link
Collaborator

fflaten commented Sep 1, 2021

This is off-topic but I'm very curious. What kind of sorcery are you doing in BeforeAll? A module unloading itself in it's own module scope? 😕

@plastikfan
Copy link
Contributor Author

plastikfan commented Sep 2, 2021

mmm, yeah I admit that was a mistake (unloading the module inside the BeforeAll block), but it made no difference correcting that aspect, which actually had nothing to do with anything.

On the parameter binding issue, yeah I think I screwed that up, but couldnt see the wood for the trees. However, one thing that I have learnt from this is that the with respect to template parameters, the documentation is misleading. From the documentation, I thought that the declaration of the template variables come from the angle brackets inside the It/Content title in this case:

Context 'given: <UndoRenameDisabled>, <EliziumPath>' {

Instead, the declaration just comes from the TestCase definition. I only discerned this from your code sample and actually the template variable expansion has nothing to do with data driven test cases, where as I thought it was central to the way these types of tests should be defined.

@plastikfan
Copy link
Contributor Author

PS: I'm going to close this issue. @nohwnd is there anythng I should know about updating the documentation and submitting a pull request, apart from what I have found about simply updating .mdx files? What I mean is, I am hoping that all I need to do is update .mdx files without having to install and run docusauras or any other client side dependencies.

@plastikfan
Copy link
Contributor Author

Also, is there a way to access $TestDrive during discovery phase? At the moment, to me there doesnt appear to be so, which means TestCase template parameters can't be populated with TestDrive, eg $(Join-Path -Path $TestDrive -ChildPath 'child') does not work. As it stands, I'm gonna have to think of a convoluted work-asround unless there is already an idiomatic solution to this.

@fflaten
Copy link
Collaborator

fflaten commented Sep 2, 2021

Also, is there a way to access $TestDrive during discovery phase?

This was recently discussed in #1829. I hope some of the comments might help you.

@plastikfan
Copy link
Contributor Author

Ok thanks @fflaten

@nohwnd
Copy link
Member

nohwnd commented Sep 2, 2021

PS: I'm going to close this issue. @nohwnd Jakub Jares FTE is there anythng I should know about updating the documentation and submitting a pull request, apart from what I have found about simply updating .mdx files? What I mean is, I am hoping that all I need to do is update .mdx files without having to install and run docusauras or any other client side dependencies.

You can just change the mdx files. But the config items in New-ConfigurationItem are generated, and all the cmdlet specific files in command reference are generated. But you won't be touching any of those. If you do change it in Pester repo, either in the csharp code, or in the inline help for the respective command.

@nohwnd
Copy link
Member

nohwnd commented Sep 2, 2021

When template like <UndoRenameDisabled> is used in Context / Describe it would be expanded from an existing variable that is already in context, or from -foreach that you provided to that context, or from the BeforeAll of that context.

@plastikfan
Copy link
Contributor Author

Thanks @nohwnd, that's what I thought. The data driven test case facility uses this variable expansion feature as opposed to to being the other way around (the template syntax defining the variables to be used in testcases which I originally thought)

@fflaten
Copy link
Collaborator

fflaten commented Dec 15, 2021

Hi @plastikfan. Would you still like to submit some updates here (if in command reference) or in pester/docs repo to make the template syntax clearer? 🙂

@fflaten fflaten removed the Feature label Jul 3, 2022
@fflaten fflaten closed this as completed Jul 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants