-
-
Notifications
You must be signed in to change notification settings - Fork 469
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
Test fails while it should pass #1873
Comments
@DarkLite1 for me only the last two fail. Is what you described as current behavior: "First test fails." incorrect? |
It fails for you because only BoundParameters are set as variables in the ParameterFilter. You are using variable with the same name as the parameter which is set to 5 after the foreach loop. Foreach does not create a new scope, so the variable remains in scope. This variable is inherited into the it 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$san = 'a'
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$SamAccountName -eq $san
}
} So in your example, you have two calls of Get-Stuff. You get 2 matching, but you asked to have exactly 1. Describe 'test' {
BeforeAll {
Function Get-Stuff {
Param (
[String]$SamAccountName,
[String]$DistinguishedName
)
}
Mock Get-Stuff
}
it 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
foreach (
$samAccountName in (0..5) # rename the variable and it works
) {
# do something
}
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
Write-Host "`$SamAccountName is $($SamAccountName), will pass filter? $([bool]$SamAccountName)" -ForegroundColor Cyan
$SamAccountName
}
}
}
I don't think this is a bug. |
Btw running this with the Diagnostic output will help diagnosing this as well:
|
Thank you for getting back to me. I now fully understand where we went wrong. So thanks for the clarification and the very clear example that showed my stupidity of staring too long to my code lol. You are correct, it can be that we want to access variables within the Looking at this from another perspective it seemed really strange because It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$SamAccountName = $false
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$SamAccountName
}
} This does not as you just explained to me, we unintentionally added the variable to the scope which makes the test fail: In real life this was intentional because we have a test script file that we want to test where we really use a It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$SamAccountName = $true
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$SamAccountName
}
} Just an idea, but it would be great if there was a parameter t's just a thought but something like this might clear up all possible confusion. A small example to clarify the idea: It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$samAccountName = 'a'
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$mockParameter.SamAccountName -eq $samAccountName
}
} PS: Thanks for the |
That sounds interesting. But $mockParameter would have to include all variables that are inherited to the current scope from all parents, so that hashtable would be big, and I would have to build it everytime a parameter filter is about to be invoked. This seems slow. It also brings more problems to the table. What if your variable is not in the table for some reason, maybe there is a typo or something. It think a more reasonable solution to this is to add a logging which will check if the parameter variable we are about to define already exists and log that. This will only impact Diagnostic runs, and should show you that "Parameter $SamAccountName defined variable with value "a", but the value already existed in the current scope and had value "5", are your test variables conflicting with parameter names?". This covers the case when the variable conflicts with a parameter name that was provided. What this does not cover is when variable does not conflict with the parameter name. (in your |
Thank you for getting back to me. Really appreciate that you're open to suggestions.
Why would it be needed to include all variables from the parent scopes in UPDATE: I'm wrong, this will not work.... You are correct, it seems like you have to rebuild the |
It's hard for me to distinguish a mistake from intent when I don't understand the motivation. That's why I suggest better logging, so when you see that something is wrong (because you know the intent and can identify a mistake), you have better tools to see what might be wrong. |
Yeah, I understand. That's why it's a great idea to use a hashtable for the parameters that are mocked. It might be slower but it will guarantee that people are addressing the parameter and not another variable somewhere else. When using something like It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$samAccountName = 'a'
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$mockParameter.SamAccountName -eq $samAccountName
}
} In that case there is no diagnostic logging required to see the variables or the values they hold. The hashtable is just holding the |
@DarkLite1, that would be a serious braking change, affecting mocks that do not depend on variables in the parent scope. Wouldn't it be more intuitive, if it was implemented the other way around, where you'd have to specify required variables from the parent scope more explicitly, i.e. with the help of a It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$samAccountName = 'a'
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$SamAccountName -eq $using:samAccountName
}
} |
Will implement the logging as proposed. I will look into the psboudn parameters later. But the $using won't work imho, because we are running the the same scope, not in other scope. |
Thank you @nohwnd for improving the logging. Also thank you @Glober777 for thinking out of the box one this one. Shame it doesn't work with Can we maybe keep this one open until we have a way to really address the arguments of a function in the |
Lets say we update the mocking docs to advise using Sample using $PesterBoundParameters: It 'should pass because argument SamAccountName is only called once' {
Get-Stuff -SamAccountName 'a'
Get-Stuff -DistinguishedName 'b'
$expectedSamAccountName = 'a'
Should -Invoke Get-Stuff -Times 1 -Exactly -ParameterFilter {
$PesterBoundParameters.SamAccountName -eq $expectedSamAccountName
}
} |
@fflaten if we advice in the docs to use Adding a warning message for using the same variable name in the IMHO it would be best practice to always use Thank you for implementing this guys, really appreciate it. |
It is very new so not unexpected :-)
I'll submit a docs PR to mention this in a tip admonitions (green block).
I like the idea as a diagnostic-output warning. What do you think @nohwnd ? |
I like it, it was my idea :D #1873 (comment) It does not work at the moment though, because when running the filter we are already in the function, so we already have that parameter defined. |
Haha, my bad 😅 |
General summary of the issue
Hard to explain, but it took us a complete breakdown of a very complicated script to see what was happening. Please see the test code below.
Describe your environment
Steps to reproduce
The code below should pass for all tests but it reports the following errors:
It seems like the parameter used in the function called
$SamAccountName
cannot be used as variable names in other places in the script outside of the function or it will break the check on how many times the function/mock is called.Expected Behavior
Expected all tests to pass.
Current Behavior
First test fails.
The text was updated successfully, but these errors were encountered: