简体   繁体   English

PowerShell模块函数无法访问调用者范围内的变量

[英]PowerShell module functions cannot access variables in caller's scope

I'm using Pester with Selenium WebDriver. 我正在将Pester与Selenium WebDriver一起使用。 WebDriver is initialized in 'BeforeAll' block within corresponding 'Describe' block and the resulting instance is assigned to $driver variable. WebDriver在相应的'Describe'块中的'BeforeAll'块中初始化,并将生成的实例分配给$ driver变量。 Then, in 'Describe' and 'It' block I call my custom functions that reside in external PowerShell module that is autoloaded with PowerShell. 然后,在“描述”和“它”块中,我调用自定义函数,这些函数位于随PowerShell自动加载的外部PowerShell模块中。 I expect that these functions have access to $driver variable defined in 'BeforeAll' block, but it does not happen and I get the following error message: 我希望这些函数可以访问在'BeforeAll'块中定义的$ driver变量,但是不会发生,并且会出现以下错误消息:

RuntimeException: You cannot call a method on a null-valued expression. RuntimeException:您不能在空值表达式上调用方法。

Here is the code from Search.Tests.ps1 Pester script: 这是Search.Tests.ps1 Pester脚本中的代码:

Describe "Search for something" -Tag something {    

BeforeAll {
    $driver = New-WebDriver
    $driver.Navigate().GoToUrl('http://example.com')
}

AfterAll {
    $driver.Close()
    $driver.Dispose()
    $driver.Quit()
}

Find-WebElement -Selector ('some_selector')

    It "Something is found in search results" {
        GetTextFrom-WebElement -Selector ('some_selector') | Should Be 'something'
    }
}

Find-WebElement and GetTextFrom-WebElement are helper functions that use $driver to get element by CSS and extract element's inner text. Find-WebElement和GetTextFrom-WebElement是使用$ driver通过CSS获取元素并提取元素内部文本的辅助函数。

I investigated the issue and found a workaround, but I don't think it's an elegant way to go. 我对此问题进行了调查并找到了解决方法,但我认为这不是一个优雅的方法。 The workaround is to redefine $driver in each helper function in the external PowerShell module right after the param block like this: 解决方法是在param块之后,在外部PowerShell模块的每个帮助器函数中重新定义$ driver,如下所示:

$driver = $PSCmdlet.GetVariableValue('driver')

This way the functions can see $driver and everything works. 这样,函数可以看到$ driver并且一切正常。

My question: is it possible to do something, so the functions always have access to $driver without a need to redefine driver in each of them? 我的问题是:是否有可能做点什么,所以这些函数始终可以访问$ driver而不需要在每个函数中重新定义驱动程序?

"I expect that these functions [defined in a PowerShell module] have access to $driver variable defined in 'BeforeAll' block..." “我希望这些功能(在PowerShell模块中定义)可以访问'BeforeAll'块中定义的$ driver变量...”

They don't, and you probably shouldn't rely on that behaviour even if they did. 他们没有,即使他们这样做,您也可能不应该依赖这种行为。

Variables Defined in Pester Scriptblocks Aren't Accessible from Modules 无法从模块访问Pester脚本块中定义的变量

Variables defined in BeforeAll{} , BeforeEach{} , Context{} , and It{} blocks are not accessible from a module under test when the x.Tests.ps1 file is invoked by Invoke-Pester ( reference ). x.Tests.ps1文件由Invoke-Pester参考 )调用时, 无法从被测模块访问BeforeAll{}BeforeEach{}Context{}It{}块中定义的变量。 If the x.Tests.ps1 file happens to be invoked directly (ie. by pressing F5 in ISE) then variables defined in BeforeAll{} are accessible from a module under test. 如果x.Tests.ps1文件恰好被直接调用(即,通过在ISE中按F5键 ),则可以从被测模块访问BeforeAll{}中定义的变量。 Relying on that behavior precludes that test from running in bigger batches, so should be avoided. 依靠该行为可以阻止测试大批量运行,因此应避免。

Reliance of Implicit Accessibility of External Variables Should be Avoided 应避免依赖外部变量的隐式可访问性

It seems like your custom module expects that $driver is defined somewhere outside the module and is implicitly accessible from inside the module. 似乎您的自定义模块希望$driver在模块外部的某个位置定义,并且可以从模块内部隐式访问。 That raises the following question: Where did the author of the custom module intend $driver to be defined? 这就提出了以下问题:定制模块的作者打算在哪里定义$driver As a script variable in the module? 作为模块中的脚本变量? As a global variable? 作为全局变量? Both of those are pretty awkward public interfaces for a module because it is difficult to control whether the correct value for $driver is indeed available to the module. 这两个都是模块的非常尴尬的公共接口,因为很难控制$driver的正确值是否确实可用于该模块。 If the module does rely on such behavior, I suggest changing the custom module to explicitly accept your $driver object (or at least the information required to create that object). 如果模块确实依赖于这种行为,则建议更改自定义模块以显式接受$driver对象(或至少接受创建该对象所需的信息)。

If you cannot change the custom module, you might be able to get by with changing your variable references from $driver to $global:driver . 如果您不能更改自定义模块,则可以将变量引用从$driver更改为$global:driver You should really try to avoid that though, because using global variables in that way will likely result in any of a variety of problems at some point. 但是,您应该真正避免这种情况,因为以这种方式使用全局变量可能会在某个时候导致各种问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM