Unit Testing PowerShell Code with Pester
Summary: Guest blogger, Dave Wyatt, discusses using Pester to analyze small pieces of Windows PowerShell code.
Note This 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 with Pester
Use Pester to analyze small pieces of Windows PowerShell code - Testing Script Modules with Pester
Use Pester for testing PowerShell modules - More Pester Features and Resources
Learn about more Pester resources
Before we get into the technical details today, let’s define a few terms. There are several categories of automated testing, all of which are used in a continuous delivery pipeline. For the purposes of Windows PowerShell code, I tend to refer to three:
- Unit tests
- Integration tests
- Acceptance tests
Unit tests
A unit test is the smallest and fastest type, and it is the first thing that will be run in your pipeline. It can usually be executed on the developer’s machine before checking in the code to source control. Unit tests are responsible for verifying the behavior of a single unit of code, which in PowerShell, typically means a function.
If the function you are testing depends on anything other than the parameters that are passed in, you’ll want to isolate your code from those other dependencies in the unit test. These dependencies could be anything, including a web service of some sort, the state of the computer where the script runs, or even calls to other PowerShell functions or cmdlets.
Integration tests
Integration tests are pretty much the opposite of unit tests. Instead of isolating your code from the other parts, you run everything in all its glory, and make sure it’s behaving properly when all of the bits are working together. This might require you to set up a more complicated test environment, so the necessary web services, for example, are available. This means that integration tests are more expensive to run. It’s for this reason that you only move on to integration tests if the unit tests have already passed.
Acceptance tests
Acceptance tests are fundamentally the same as integration tests, except they refer to tests that you run after your code is deployed into production. You can use them as a quick sanity check to make sure everything’s up and running. You might also hear these referred to as “smoke tests.”
The examples of Pester that you’ve seen so far are perfect for integration or acceptance tests. They make calls to an API (without caring what its internals do), and write test cases against the results. For a unit test, though, we need some way of isolating our function under test from its dependencies. That’s where mocking comes into play.
Pester has a built-in mocking framework that allows you to create dummy versions of other PowerShell commands. A picture is worth a thousand words, so here’s a sample of a PowerShell function that needs some mocking to be properly unit tested:
This is a fairly simple function, but it contains calls to four other cmdlets: Get-Date, Get-ADUser, Where-Object, and Disable-ADAccount. Of these, we can ignore Where-Object because it’s simply a logic construct—and indeed, it is what we’re testing. (The function is written this way instead of using the better Search-ADAccount cmdlet simply to give us more to work within the Pester examples.)
To test this code without requiring an actual Active Directory domain, we need to consider a few things:
- Make Get-Date return a specific date and time. (This is optional, but not a bad idea.)
- Make Get-ADUser return a set of test objects. We want some of these to be “disabled,” and others should be left alone. The test cases will make sure the proper objects are passed to Disable-ADAccount.
- Make Disable-ADAccount do nothing, other than give us a way to track how it was called, so we know which users would be disabled.
Here’s what this might look like:
In this example, we’re seeing two new Pester commands: Mock and Assert-MockCalled. When you use Mock, you temporarily replace the behavior of a PowerShell command with whatever you want it to be. Mock is active only inside the Describe or Context block where it is defined. If we had another Describe block in the example, Get-Date, Get-ADUser, and Disable-ADAccount would go back to their normal behavior. When Mock was called on Disable-ADAccount, we didn’t even bother to specify an implementation; it defaults to doing nothing.
In my experience, most mocks fall into one of these two categories: You either want them to return objects that your tests define, or you want them to do nothing (and then later verify how they were called). I can’t think of a situation where I’ve had a mock return output later and be verified via the Assert-MockCalled command because those tests would be redundant.
There are a few things to notice about mocking…
- Notice that I didn’t need to specify any parameter blocks for my mocks—and indeed, you should not even try to do that. This is because Pester will examine the original command that’s being mocked, and it will inject its parameters (including dynamic parameters) into the mock for you automatically.
- The Mock and Assert-MockCalled commands have a parameter called –ParameterFilter. This allows you to control under what circumstances the mock is effective (or whether the assertion should succeed or fail), based on the parameters that are used when the mock is called. Incidentally, you can mock the same command multiple times, with different parameter filters and different implementations, if you need to.
- Mocking works by taking advantage of the command resolution order in Windows PowerShell, as detailed in theabout_Command_Precedence Help file. When multiple PowerShell commands exist with the same name, the function version will be executed instead of cmdlets or external commands. When you define a mock in Pester, it creates a function with the name of the command that you want to mock, and that will be what gets executed instead of the original command.
It’s important to understand how this works, because your scripts might need some small modifications to work well with mocking in Pester. For example, let’s revise our Active Directory example slightly:
In this version, the calls to Get-ADUser and Disable-ADAccount have been module-qualified (in ActiveDirectory\Get-ADUser). This gives PowerShell some extra information about which command to execute, and causes it to skip your mocked command and execute the live commands instead.
To make the code friendly to mocking, you’d need to remove the module-qualified calls. Or you can wrap those calls in your own internal function, which can be mocked instead of the Active Directory cmdlets. Wrapping code into a function to facilitate mocking is a pretty common occurrence, such as if you want to mock calls to a .NET class or method (which Pester can’t do).
There are other nuances to the Mock and Assert-MockCalled commands, some of which we’ll talk about tomorrow when we look at unit testing code in script modules. To find more help and information about Pester, see:
- Pester Help files
- Pester Home page and Pester Powershell BDD style testing framework on GitHub
- Pester Group on Google
~Dave
Thanks, Dave!
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Unit Testing PowerShell Code with Pester的更多相关文章
- 学习笔记之Unit testing/Integration testing/dotnet test and xUnit
source code https://github.com/haotang923/dotnet/tree/master/src Unit testing C# code in .NET Core u ...
- 10 Unit Testing and Automation Tools and Libraries Java Programmers Should Learn
转自:https://javarevisited.blogspot.com/2018/01/10-unit-testing-and-integration-tools-for-java-program ...
- Unit Testing with NSubstitute
These are the contents of my training session about unit testing, and also have some introductions a ...
- [Java Basics3] XML, Unit testing
What's the difference between DOM and SAX? DOM creates tree-like representation of the XML document ...
- Javascript单元测试Unit Testing之QUnit
body{ font: 16px/1.5em 微软雅黑,arial,verdana,helvetica,sans-serif; } QUnit是一个基于JQuery的单元测试Uni ...
- [Unit Testing] AngularJS Unit Testing - Karma
Install Karam: npm install -g karma npm install -g karma-cli Init Karam: karma init First test: 1. A ...
- C/C++ unit testing tools (39 found)---reference
http://www.opensourcetesting.org/unit_c.php API Sanity AutoTest Description: An automatic generator ...
- Unit Testing a zend-mvc application
Unit Testing a zend-mvc application A solid unit test suite is essential for ongoing development in ...
- VS2010(2012)中使用Unit Testing进行单元测试
原文 VS2010(2012)中使用Unit Testing进行单元测试 使用VS 2012自带的Unit Testing工具进行单元测试是非常方便的.网上关于这方面的例子很多,这篇随笔只起个人学习笔 ...
随机推荐
- codeforces 401D (数位DP)
思路:很明显的数位dp,设dp[i][j] 表示选取数字的状态为i,模m等于j的数的个数,那么最后的答案就是dp[(1<<n)-1][0].状态转移方程就是,dp[i|(1<< ...
- [MySQL-1] mysql error 1101 blob/text column can't have a default value
在MySQL Query Browser上创建一个含有TEXT类型的字段,创建不成功,报错:mysql error 1101 blob/text column can't have a default ...
- (一)NUnit单元测试心得
由于各种缘由,一本<.Net单元测试艺术>突然出现在了我的办公桌上,于是我的单元测试之路就此开始.通过一两个月不间断的学习,以及不断结合具体的项目做开发,再结合书上的知识对单元测试有了一些 ...
- CentOS 7.0 安装 python3.X 脚本
#!/bin/sh #第一个Linux下的脚本,太多不明白的地方,只是依着网上的例子照葫芦画瓢,能正常运行即可 #运行环境 CentOS 7.0 版本 #首行指定程序的路径,以#号开头的行是注释行 # ...
- 超级MINI STLINK V2 官方固件自动升级 ST-Link 【worldsing 笔记】
简介: 支持所有带SWIM接口的STM8系列单片机 支持所有带SWD接口的STM32系列单片机 完全兼容Keil,STVP,STVD,IAR,COSMIC,STM32 ST-LINK Utility! ...
- jquery完成带复选框的表格行高亮显示
jquery完成带复选框的表格行高亮显示 通过jquery技术来操作表格是件简单的事,通过jquery的语法,可以很轻松的完成表格的隔行换色,悬浮高亮,在实际的应用中可能会出现表格中带复选框的,删除时 ...
- 一步一步学android控件(之十五) —— DegitalClock & AnalogClock
原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...
- 【STL学习】智能指针之shared_ptr
前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择 几乎所有的程序都需要某种形式的引用计数智能指 ...
- git 快速入门(二)
一.引子 git代码托管的优秀工具之一, 其工作原理和svn截然不同.一旦拥有主干master分支权限, 只要在本地拉取主干分支, 可以随时随地切换分支. 它拥有众多优点,eg :支持在断网的情况下, ...
- js获取上传文件内容(未完待续)
js 获取上传文件的字节数及内容 <div> 上传文件 : <input type="file" name = "file" id = &qu ...