{"id":75031,"date":"2015-12-17T00:01:00","date_gmt":"2015-12-17T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/12\/17\/testing-script-modules-with-pester\/"},"modified":"2022-11-17T07:41:02","modified_gmt":"2022-11-17T15:41:02","slug":"testing-script-modules-with-pester","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/testing-script-modules-with-pester\/","title":{"rendered":"Testing Script Modules with Pester"},"content":{"rendered":"<p><strong>Summary<\/strong>: Dave Wyatt discusses using Pester for testing PowerShell modules.<\/p>\n<p><strong>\u00a0 \u00a0Note<\/strong>\u00a0\u00a0\u00a0This is a five-part series that includes the following posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/what-is-pester-and-why-should-i-care\/\" target=\"_blank\" rel=\"noopener\">What is Pester and Why Should I Care?<\/a><br \/>\nLearn about a new test framework for PowerShell called Pester<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/getting-started-with-pester\/\" target=\"_blank\" rel=\"noopener\">Getting Started with Pester<\/a><br \/>\nLearn how to get information back from Pester<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/unit-testing-powershell-code-with-pester\/\" target=\"_blank\" rel=\"noopener\">Unit Testing PowerShell Code with Pester<\/a><br \/>\nUse Pester to analyze small pieces of Windows PowerShell code<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/testing-script-modules-with-pester\/\" target=\"_blank\" rel=\"noopener\">Testing Script Modules with Pester<\/a><br \/>\nUse Pester for testing PowerShell modules<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/more-pester-feature-and-resources\/\" target=\"_blank\" rel=\"noopener\">More Pester Features and Resources<\/a><br \/>\nLearn about more Pester resources<\/li>\n<\/ul>\n<p>Yesterday, we looked at how to use the <strong>Mock<\/strong> and <strong>Assert-MockCalled<\/strong> commands in Pester to unit test the logic in your PowerShell code without having any external dependencies. This can get a little bit trickier when you start to store your code in script modules (.psm1 files). To demonstrate this, I\u2019ve taken the code from yesterday\u2019s Active Directory example, placed it into a .psm1 file, and added a small change to introduce an internal function:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5482.1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5482.1.png\" alt=\"Image 5482 1\" width=\"607\" height=\"378\" class=\"alignnone size-full wp-image-87973\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5482.1.png 607w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5482.1-300x187.png 300w\" sizes=\"(max-width: 607px) 100vw, 607px\" \/><\/a><\/p>\n<p>The Tests.ps1 file is fine as-is, with the small exception of calling <strong>Import-Module<\/strong> instead of dot-sourcing a .ps1 file on the first line. For a refresher, here\u2019s what that tests file currently looks like:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/6835.2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/6835.2.png\" alt=\"Image 6835 2\" width=\"628\" height=\"326\" class=\"alignnone size-full wp-image-87975\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/6835.2.png 628w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/6835.2-300x156.png 300w\" sizes=\"(max-width: 628px) 100vw, 628px\" \/><\/a><\/p>\n<p>Here\u2019s what happens if I run <strong>Invoke-Pester<\/strong> on this file as-is:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5238.3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5238.3.png\" alt=\"Image 5238 3\" width=\"626\" height=\"124\" class=\"alignnone size-full wp-image-87974\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5238.3.png 626w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/5238.3-300x59.png 300w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/a><\/p>\n<p>When this happens to you, you may understandably start cursing the incompetent people who wrote this Pester thing. You clearly mocked the <strong>Get-ADUser<\/strong> command to return a set of test objects, so why the heck did the tests try to contact an actual Active Directory server?<\/p>\n<p>But wait\u2026<\/p>\n<p>It gets even better. What happens if we try to mock or execute the internal <strong>GetUsersToDisable<\/strong> command instead?<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/3443.4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/3443.4.png\" alt=\"Image 3443 4\" width=\"614\" height=\"466\" class=\"alignnone size-full wp-image-87976\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/3443.4.png 614w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/3443.4-300x228.png 300w\" sizes=\"(max-width: 614px) 100vw, 614px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8463.5.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8463.5.png\" alt=\"Image 8463 5\" width=\"625\" height=\"183\" class=\"alignnone size-full wp-image-87977\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8463.5.png 625w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8463.5-300x88.png 300w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p>It turns out that this is due to how PowerShell script modules work. Each module has its own private scope area where it can store its functions, variables, and aliases, which is entirely separate from the scope of the caller. When you call the <strong>Mock<\/strong> command in Pester, by default, it creates the mocked function in the scope of your Tests.ps1 script. Calls to the command from inside the module never see that mock because the module has its own scopes that are separate from the script.<\/p>\n<p>Before you throw up your hands and give up on this Pester thing, let me introduce you to the <strong>InModuleScope<\/strong> command. It allows you to inject some or all of your test code into a script module, which gives you direct access to all of its internal bits and pieces. It also causes your mocks to be defined inside the module rather than in the Tests.ps1 script\u2019s scope, solving all of the problems shown in the first two examples.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8611.6.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8611.6.png\" alt=\"Image 8611 6\" width=\"632\" height=\"331\" class=\"alignnone size-full wp-image-87979\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8611.6.png 632w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/8611.6-300x157.png 300w\" sizes=\"(max-width: 632px) 100vw, 632px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1731.7.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1731.7.png\" alt=\"Image 1731 7\" width=\"604\" height=\"115\" class=\"alignnone size-full wp-image-87978\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1731.7.png 604w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1731.7-300x57.png 300w\" sizes=\"(max-width: 604px) 100vw, 604px\" \/><\/a><\/p>\n<p>If you\u2019re looking through the Help files in Pester, you may notice that there\u2019s another way to accomplish a similar task: both the <strong>Mock<\/strong> and <strong>Assert-MockCalled<\/strong> commands have a <strong>\u2013ModuleName<\/strong> parameter, which allows you to inject a mock into a module and then verify its calls. This was written before the <strong>InModuleScope<\/strong> command. However, it didn\u2019t solve the problem of being able to call a module\u2019s internal functions directly, so they can be unit tested separately from the exported functions.<\/p>\n<p>The <strong>InModuleScope<\/strong> command is the newer and simpler way of accomplishing this. Any time I\u2019m writing a set of tests for a script module, I write two lines at the top of the Tests.ps1 script to remove any existing copies of the module from the session and import the one I want to test. (The <strong>Remove-Module<\/strong> part can be important, because PowerShell will let you import two copies of the same module from different locations. Pester doesn\u2019t like that at all.)<\/p>\n<p>Everything else in the Tests.ps1 script gets wrapped in the <strong>InModuleScope<\/strong> command, as shown in the example, at which point I don\u2019t need to worry about any problems. If you use this approach, all of the tests you\u2019d expect to work with a simple .ps1 script will also work with a .psm1 script module.<\/p>\n<p>With this last piece of the puzzle, you have all of the essential tools needed to write a comprehensive suite of Pester tests for any PowerShell code (or as tests for other code that can be invoked &#95;from&#95; PowerShell).<\/p>\n<p>Pester has a few more tricks up its sleeve to help you, though. Tomorrow, I\u2019ll wrap up the series by demonstrating some of those features and by taking a look at some of the upcoming features planned for Pester 4.0.<\/p>\n<p>~Dave<\/p>\n<p>Thanks, Dave. Pester is an awesome tool!<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\" rel=\"noopener\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\" rel=\"noopener\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\" rel=\"noopener\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\" rel=\"noopener\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong>\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Dave Wyatt discusses using Pester for testing PowerShell modules. \u00a0 \u00a0Note\u00a0\u00a0\u00a0This is a five-part series that includes the following posts: What is Pester and Why Should I Care? Learn about a new test framework for PowerShell called Pester Getting Started with Pester Learn how to get information back from Pester Unit Testing PowerShell Code [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[501,56,636,45],"class_list":["post-75031","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-dave-wyatt","tag-guest-blogger","tag-pester","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Dave Wyatt discusses using Pester for testing PowerShell modules. \u00a0 \u00a0Note\u00a0\u00a0\u00a0This is a five-part series that includes the following posts: What is Pester and Why Should I Care? Learn about a new test framework for PowerShell called Pester Getting Started with Pester Learn how to get information back from Pester Unit Testing PowerShell Code [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/75031","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=75031"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/75031\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=75031"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=75031"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=75031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}