Powershell 的堆栈跟踪是否已损坏?
我正在 powershell 中编写一个简单的单元测试工具,
我设计了该工具,使其断言函数将脚本块作为参数,以允许工具从断言函数内运行代码,并将抛出的任何异常视为测试失败。
如果测试失败,我想返回测试失败的单元测试中的行。我的计划是通过在每个断言方法的开头进行堆栈跟踪 (Get-PSCallStack) 并使用第二个堆栈帧的信息来实现此目的,我认为该信息应与调用断言函数的行相对应。
在实践中,我发现powershell返回的信息似乎有误。第二个堆栈帧按预期引用正确的文件,但始终给出我在断言方法中调用 Get-PSCallStack 的行号。有时,这个数字可能甚至高于给定文件中的行数(即,位置给出为“ScriptFile.ps1 line 88”,但文件只有 20 行)。
powershell 中的堆栈跟踪是否有问题,或者有什么我不明白的地方?
编辑
根据要求,我发布了一个示例,该示例应产生相同的结果
Tester.ps1
#File 1 (Tester.ps1)
#Creates the tester object
$tester = (New-Object PSObject);
$tester | Add-Member -MemberType ScriptMethod -Name AssertTrue -Value {
param($expression);
$stackFrame = (GEt-PSCallStack)[1];
try{
$result = &$expression;
if($result -eq $true){
$this.LogPass();
}else{
$this.LogFailure("Evaluation Failed expected ""$true"" got ""$false""", $stackFrame);
}
}catch [Exception]{
$this.LogFailure("Unexpected exception encountered", $stackFrame);
}
}
$tester | Add-Member -MemberType ScriptMethod -Name LogPass -Value {
#Do nothing
};
$tester | Add-Member -MemberType ScriptMethod -Name LogFailure -Value {
param($message, $stackFrame);
"Failure Encounterd";
"Command: $($stackFrame.Command)"
"Location: $($stackFrame.Location)";
"Message: $message";
}
return $tester;
TestCase.ps1
#File 2 (TestCase.ps1)
#Runs the tests using the tester object
$tester = &(Resolve-Path "Tester.ps1");
function TestFailure($tester){
$expression = {$false};
$tester.AssertTrue($expression);
}
TestFailure($tester);
在 TestCase.ps1 的第 7 行调用断言,并在 Tester 的第 9 行捕获调用堆栈。 ps1
这打印
Failure Encounterd
Command: TestFailure
Location: Tester.ps1: Line 9
Message: Evaluation Failed expected "True" got "False"
命令是正确的,但文件和行都是错误的
堆栈跟踪的下一帧正确描述了调用 TestFailure() 的位置,其位置为“TestCase.ps1:第 11 行”
I am writing a simple unit test harness in powershell
I designed the harness such that its assert functions takes a script-block as a parameter to allow the harness to run the code from within the assert function and treat any exceptions are thrown as a test failure.
If the tests fail I want to return line in the unit test in which the test fails. My plan was to do this by taking a stacktrace (Get-PSCallStack) at the start of each assert method and use the information for the second stack-frame which I assume should correspond to the line where the assert function was called.
In practice, I found that the information that powershell gave back seemed wrong. The second stack-frame refers to the the correct file as expected but always gives the line number at which I called Get-PSCallStack in the assert method. Sometimes this number might be even higher than the number of lines in the file given (i.e. Location is given as "ScriptFile.ps1 line 88" but the file only has 20 lines).
Is there a problem with the stack trace in powershell or is there something I am not understanding here?
Edit
As requested I am posting an example which should produce the same results
Tester.ps1
#File 1 (Tester.ps1)
#Creates the tester object
$tester = (New-Object PSObject);
$tester | Add-Member -MemberType ScriptMethod -Name AssertTrue -Value {
param($expression);
$stackFrame = (GEt-PSCallStack)[1];
try{
$result = &$expression;
if($result -eq $true){
$this.LogPass();
}else{
$this.LogFailure("Evaluation Failed expected ""$true"" got ""$false""", $stackFrame);
}
}catch [Exception]{
$this.LogFailure("Unexpected exception encountered", $stackFrame);
}
}
$tester | Add-Member -MemberType ScriptMethod -Name LogPass -Value {
#Do nothing
};
$tester | Add-Member -MemberType ScriptMethod -Name LogFailure -Value {
param($message, $stackFrame);
"Failure Encounterd";
"Command: $($stackFrame.Command)"
"Location: $($stackFrame.Location)";
"Message: $message";
}
return $tester;
TestCase.ps1
#File 2 (TestCase.ps1)
#Runs the tests using the tester object
$tester = &(Resolve-Path "Tester.ps1");
function TestFailure($tester){
$expression = {$false};
$tester.AssertTrue($expression);
}
TestFailure($tester);
The assert is called on Line 7 of TestCase.ps1 and the call stack is captured on line 9 of Tester.ps1
This prints
Failure Encounterd
Command: TestFailure
Location: Tester.ps1: Line 9
Message: Evaluation Failed expected "True" got "False"
The command is correct but both the file and the line are wrong
The next frame of the stack trace correctly describes where TestFailure() is called with its location as "TestCase.ps1: Line 11"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它不是您使用的断言函数,而是用作“成员函数”的断言脚本块。但它仍然是一个脚本块。
根据此报告的问题:
https://connect.microsoft.com/PowerShell/feedback/details/531086/depending-on-how-you-invoke-a -script-block-the-inspiration-details-may-not-be-available-from-inside-the-script-block#
调用
Get-PSCallStack
时出现问题脚本块。所以,你的问题的答案可能是:是的,这是一个 PowerShell 问题。好吧,我建议你使用函数。我重构了你的脚本以使用函数(脏版本、坏名称等),它们按预期工作:
并且
It is not an assert function that you use, it is an assert script block used as a “member function”. But it is still a script block.
According to this reported issue:
https://connect.microsoft.com/PowerShell/feedback/details/531086/depending-on-how-you-invoke-a-script-block-the-invocation-details-may-not-be-available-from-inside-the-script-block#
there is something wrong with calling
Get-PSCallStack
from script blocks. So, the answer to your question is probably: yes, it is a PowerShell issue.Well, I would recommend you to use functions. I re-factored your scripts to use functions (dirty version, bad names, etc.) and they work as expected:
And