Mocking functions in modules that are imported from other modules

906 views
Skip to first unread message

Jamie Thomson

unread,
Nov 19, 2014, 9:24:03 AM11/19/14
to pes...@googlegroups.com
Hi folks,
I have a Pester test that tests a function in an imported module. That function in turn imports a second module and calls a function in the second module. I want to mock the call to the function in the second imported module but cannot figure out how to do it. I've put together a repro and am hoping that someone here can help me out.

Here are the two modules:
#RunSomething.psm1
function Run-Something {
    import-module .\RunSomethingElse.psm1
    Run-SomethingElse
}

#RunSomethingElse.psm1
function Run-SomethingElse {
    throw "Run-SomethingElse has executed!"
}

I want to mock the call to function Run-SomethingElse{}.

Here's my test:
Import-Module -Name .\RunSomething.psm1

Describe "MyTest" {    
    It "successfully mocks DoSomethingElse" {
        Mock -ModuleName RunSomethingElse -CommandName Run-SomethingElse {}
        Run-Something
        Assert-MockCalled -ModuleName RunSomethingElse Run-SomethingElse -Exactly 0
    }
    
}
Remove-Module -Name RunSomething

The test fails with error:
Describing Run-Something
 [-] MyTest 0.99s
   Could not find Command Run-SomethingElse

Hmm, so it can't find function Run-SomethingElse in module Run-SomethingElse.psm1. Fair enough, I'll try and import that module into my test:
Import-Module -Name .\RunSomething.psm1
Import-Module -Name .\RunSomethingElse.psm1 #added this line

Describe "Run-Something" {    
    It "MyTest" {
        Mock -ModuleName RunSomethingElse -CommandName Run-SomethingElse {}
        Run-Something
        Assert-MockCalled -ModuleName RunSomethingElse Run-SomethingElse -Exactly 0
    }
    
}
Remove-Module -Name RunSomethingElse #added this line
Remove-Module -Name RunSomething
This time the deliberate error from the function that I am attempting to mock gets thrown:
 [-] MyTest 1.21s
   Run-SomethingElse has executed!

Clearly the code did not get mocked! I wonder if I can change the behaviour by changing the point at which Run-SomethingElse() gets imported by Run-Something(). So here is my modified Run-Something.psm1:
#RunSomething.psm1
import-module .\RunSomethingElse.psm1 #import-module command moved out of the function
function Run-Something {
    Run-SomethingElse
}
and my test:
Import-Module -Name .\RunSomething.psm1

Describe "Run-Something" {    
    It "MyTest" {
        Mock -ModuleName RunSomethingElse -CommandName Run-SomethingElse {}
        Run-Something
        Assert-MockCalled -ModuleName RunSomethingElse Run-SomethingElse -Exactly 0
    }
    
}
Same output:
 [-] MyTest 1.74s
   Run-SomethingElse has executed!
the function is still not getting mocked!

Any suggestions as to what I am doing wrong here? I'm sure I'm missing something obvious but right now I'm perplexed.

TIA
JT





Dave Wyatt

unread,
Nov 19, 2014, 9:29:44 AM11/19/14
to pes...@googlegroups.com
You're on the right track.  You do need to import the "inner" module first, because the Mock command fails if the original command can't be found at the time the mock is created.
 
Where you're going wrong is with the -ModuleName parameter.  That should be the name of the module where the _calls_ to the mocked command are coming from, not the module where the original command was defined.  So here, you should be fine with:
 
Mock -ModuleName RunSomething -CommandName Run-SomethingElse {}
 
This will mock any calls to Run-SomethingElse from inside the RunSomething module.

Jamie Thomson

unread,
Nov 19, 2014, 9:41:35 AM11/19/14
to pes...@googlegroups.com
Hi again Dave,
Thanks for the reply. Sorted now:
#RunSomething.psm1
import-module .\RunSomethingElse.psm1 #import-module command moved out of the function
function Run-Something {
    Run-SomethingElse
}
#RunSomethingElse.psm1
function Run-SomethingElse {
    throw "Run-SomethingElse has executed!"
}
Import-Module .\RunSomething.psm1

Describe "Run-Something" {    
    It "MyTest" {
        Mock -ModuleName RunSomething -CommandName Run-SomethingElse {}
        Run-Something
        Assert-MockCalled -ModuleName RunSomething Run-SomethingElse -Exactly 1
    }
}
Remove-Module RunSomething



Thank you very very much.

it does mean I'm going to have to go and refactor quite a bit of code because I've got Import-Module DoSomethingElse.psm1 in the wrong place in quite a few places. oh well.

Thanks again

JT

Dave Wyatt

unread,
Nov 19, 2014, 9:47:05 AM11/19/14
to pes...@googlegroups.com
Personally, I put those sorts of dependencies either at the very beginning of a PSM1 file (rather than inside a function), or in the RequiredModules attribute of a manifest. That way the other modules are available as soon as the "outer" module is imported, and this doesn't become a problem.

Jamie Thomson

unread,
Nov 19, 2014, 10:05:37 AM11/19/14
to pes...@googlegroups.com
Hi Dave,
Yeah, fair enough, I'll do that from now on.
the reason I had it inside the function is because I am also importing another module however the name of that other module is dependent on a parameter. As I already had one import-module inside the function I figured I might as well put the other in as well. Here's my "real" code:
function Set-NLSHDFSStore (){
[CmdletBinding()]
Param([Parameter(Mandatory=$true)][string]$environment,[string]$sourceFolderName="hdfs")
Import-Module (Get-ChildItem . -Recurse | Where-Object {$_.Name -eq "DeployUtilities.psm1"} | Sort-Object $_.FullName -Descending | Select-Object FullName -First 1 | foreach {$_.FullName})
Import-Module (Get-ChildItem . -Recurse | Where-Object {$_.Name -eq "$environment.environmentproperties.psm1"} | Sort-Object $_.FullName -Descending | Select-Object FullName -First 1 | foreach {$_.FullName})
#etc...
}

I can move importing of DeployUtilities.psm1 outside of the function but importing of $environment.environmentproperties.psm1 is going to have to stay inside. In the case of these tests that's OK becuase the function that I want to mock is inside DeployUtilities.psm1.
Reply all
Reply to author
Forward
0 new messages