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

Unable to fully mock Get-Credential #296

Closed
colinbate opened this issue Mar 24, 2015 · 8 comments
Closed

Unable to fully mock Get-Credential #296

colinbate opened this issue Mar 24, 2015 · 8 comments

Comments

@colinbate
Copy link

While you can get around this by wrapping the call to Get-Credential in another function, I figured it was worth mentioning. In version 3.3.6 I can't seem to fully mock the call to Get-Credential without the credential dialog still opening up.

This test file illustrates what I mean:

function Get-UserName() {
    $creds = Get-Credential
    $creds.UserName
}

Describe 'Get-UserName' {
    It 'returns the UserName' {
        Mock Get-Credential { return @{UserName = 'myuser'} }
        $val = Get-UserName
        $val | Should Be 'myuser'
    }
}

This test will pass if you enter any value into the credential dialog and click OK, but will fail if you hit cancel. Obviously in either case it blocks the tests until some interaction occurs.

Perhaps this can't be stopped, but if so, it might be worth mentioning it somewhere.

@dlwyatt
Copy link
Member

dlwyatt commented Mar 24, 2015

Well, that's awkward. Here's what a bit of the param block for Get-Credential looks like:

    [Parameter(ParameterSetName='CredentialSet', Mandatory=$true, Position=0)]
    [pscredential]
    [System.Management.Automation.CredentialAttribute()]
    ${Credential},

When you mock a command in Pester, the param block of the original command is copied, and you just replace the implementation. The problem here is that the param block is really doing all the work; for this parameter set, the body of Get-Credential would just return the value of the $Credential parameter.

That [System.Management.Automation.CredentialAttribute()] class is what pops up the GUI and prompts you to enter a password and/or username (all before the begin/process/end blocks even start to run). It's what allows you pass in just a username string to a Credential parameter and have it prompt you to enter the password.

I have no idea how best to handle this in the general case, at the moment. For your specific example, I'd just not use the Mock command at all, and instead write:

function Get-Credential { return @{UserName = 'myuser'} }

This way you've got control over the param block, and no nonsense happens. Because you know, in your example, that the only code calling Get-Credential does so without passing any parameters, you don't need a param block anyway.

@cathalmchale
Copy link

I was having the same problem. I've read the issue a couple of times and I think the answer is simpler than stated. I understand @dlwyatt is thinking about how to solve the general problem here, but for me using Mock was still appropriate and worked just fine when expressed as:

Mock Get-Credential {
	$password = ConvertTo-SecureString 'MySecretPassword' -AsPlainText -Force
	$credential = New-Object System.Management.Automation.PSCredential ('root', $password)
	$credential
}

That's enough to stop the UI dialog popping and to return a valid object that will work with any subsequent mocking or parameter bindings.

@renehernandez
Copy link
Contributor

@cathalmchale It seems to be that this was solved somewhere in a newer release than 3.3.6. Thanks for providing an example of it working

@gerron
Copy link

gerron commented May 7, 2020

@cathalmchale Do you happen to remember the version of Pester you were using at the time? I'm still seeing this same issue in 4.10.1

@cathalmchale
Copy link

@gerron The version was 4.7.2. I'd say you're mock isn't getting used and so you get the same net effect - credential dialog pops. I most often see this when I'm mocking within modules and have multiple modules involved. You need to use InModuleScope or -Module "ModuleName" for your mocks and make sure that the mock is declared for the right module - the one that will be executing the cmdlet.

@gerron
Copy link

gerron commented May 8, 2020

@cathalmchale I'm mocking within modules with only one module being involved. I'm currently using InModuleScope with the module specified and no luck. Every other cmdlet mock is works such as Invoke-RestMethod except Get-Credential.

@cathalmchale
Copy link

@gerron is the code publicly available on github? I can have a look if you like and see if anything jumps out.

@gerron
Copy link

gerron commented May 8, 2020

@cathalmchale Thanks a lot for taking a look. Much appreciated!

https://gist.github.com/gerron/835e0a082aa4bd630ae91b5eab383e1e
I created a snippet that normalized a few things to not disclose company endpoints/info. I've even tried exactly what you mentioned verbatim from #296 (comment)

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

5 participants