Handling function libraries with Pester

63 views
Skip to first unread message

Michael Smith

unread,
Jul 27, 2014, 9:49:13 PM7/27/14
to pes...@googlegroups.com
Hi,

I'm using Pester to test code in a script that calls a function in a second script. I'm dot-sourcing the second script before calling Invoke-Pester, but its functions aren't in scope when Pester runs the tests for the first script. I gather they're in script scope, and aren't accessible from the scope of the Pester module.

In case it's not clear there's a sample here:


Everything works if I run the tests from within PowerShell ISE because it sources the functions into the global scope. But I'd like to be able to run them from a CI job command line.

In the real application I have a number of .ps1 files dot-sourced from the main program and from the unit test driver script. Some functions, like logging functions, are called from other libraries and it would be painful to mock out the calls for every test, or to duplicate dot-source the logging .ps1 from every library .ps1 that requires it. I'm wondering what others are doing in similar situations.

I could switch from dot-sourcing to modules, but I read the debugging experience for Pester-tested modules is not quite there yet (http://johanleino.wordpress.com/2013/09/25/pester-how-to-unit-test-your-powershell-modules/).

Thanks,
Mike

Dave Wyatt

unread,
Jul 27, 2014, 10:39:13 PM7/27/14
to pes...@googlegroups.com
Hi Mike,

Pester 3.0 will resolve these problems out of the box.  Your scripts will work as-is due to changes in how test code scopes are handled by the module, and you can also start to use Pester to test script modules with much less hassle.  3.0 is currently in a Beta release, which you can find on nuget at https://www.nuget.org/packages/Pester/3.0.0-beta2 or on GitHub at https://github.com/pester/Pester/tree/Beta .

One thing I ran into while testing your code with the Beta version of Pester is that we somehow wound up treating *Tests.ps1 as test files instead of *.Tests.ps1.  This had the effect of Invoke-Pester launching run-unit-tests.ps1 which launched Invoke-Pester, and so on.  I had to rename your file to avoid the loop, and I've submitted a pull request to fix that filter so test file execution goes back to its original behavior.

If you want to make this work on the older versions of Pester, just move the line that dot-sources B.ps1 into your A.Tests.ps1 script (or into A.ps1 itself, which would make a certain amount of sense; A.ps1 probably shouldn't be calling functions without making sure they're available first.)

Dave

Michael Smith

unread,
Jul 28, 2014, 2:50:05 PM7/28/14
to Dave Wyatt, pes...@googlegroups.com
Thanks Dave - I pulled a copy of the beta branch and the tests run happily now.

I didn't want to source B.ps1 from A.ps1 because I'd also be sourcing it from a dozen or more other files and couldn't find a way to prevent multiple inclusion; it seemed a bit ugly to make PS parse the file so many times. Perhaps I'm overthinking it.

Mike


--
You received this message because you are subscribed to the Google Groups "Pester" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pester+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Dave Wyatt

unread,
Jul 28, 2014, 2:55:52 PM7/28/14
to pes...@googlegroups.com, dlwya...@gmail.com, mic...@hurts.ca
That's one of the advantages to putting your code in a script module, instead of dot-sourcing a ps1 file.  If you run Import-Module multiple times, only the first call does much of anything (unless you use the -Force switch as well.)  Dot-sourcing a script forces PowerShell to parse and compile it every time, and depending on what's in the file, may cause problems.

Scott Muc

unread,
Jul 28, 2014, 2:59:00 PM7/28/14
to Michael Smith, Dave Wyatt, pes...@googlegroups.com
I've always thought this problem is ripe for a project. Something akin to requirejs. There's a lot of lessons to be learned from Bunlder as well (http://anti-pattern.com/use-bundler-setup-instead-of-bundler-require)

Something like

Require-RelativeSource 'foo\bar.ps1'
or
Require-Source 'some\well\defined\path\file.ps1'

I like liberal use of "requires" because it provides the reader of the source code a map of where functions were defined. When I see many "requires" I tend to see it as a problem with efferent coupling.

Cheers,
Scott


Reply all
Reply to author
Forward
0 new messages