The Pester Book Chapter Review (8)

Table of Contents – Should

I finished the Should chapter in The Pester Book. As I’ve already been doing some testing with Pester, Should is a keyword, or command, in which I’m familiar, and in which I’ve used. It works this way: the Describe block, houses optional Context block(s), which house It block(s), which include an assertion. This assertion includes a PowerShell command piped to Should, that either passes or fails.

It it’s simplest form, a nested It block might look something like this example, taken almost exactly from The Pester Book.

...
    It ‘Testing 1 is an Integer:’ {
        1 | Should BeOfType [int]
    }
...

Because the numeric value of 1 is in fact an integer, this test will succeed. When Pester runs against this assertion, it’s going to pass, and produce output such as this:

...
    [+] Testing 1 is an Integer: 28ms
...

Those test results will be in green — the color of success.

The piping of our command to Should turns useable PowerShell, into Pester testing. Previously, we’ve discussed the keywords necessary to create the test framework. Now, we’re adding to our test, what’s really making it a test.

The Should keyword, or command, requires operators. We saw the -BeOfType operator in the above example. These operators, according to The Pester Book, are Be, BeExactly, BeLessThan, BeGreaterThan, BeLike, BeLikeExactly, Match, MatchExactly, BeOfType, Throw, Exist, Contain, ContainExactly, BeNullOrEmpty, and BeIn. Keep your eyes out for new ones, as Pester is continually being developed.

Remember, Should takes our assertion and determines whether it’s accurate or not. If the test is accurate, or is true, the test has passed. In reverse, if the test isn’t accurate, or is false, it has failed. Remember however, that you can have a successful test, if you’re testing for failure.

Return to Home with cd

I’ve been working in Git Bash a decent amount of my time recently, and I’ve found myself becoming used to using the cd command to return to my home directory (/c/Users/tommymaynard). Did you know you could do that? In that shell, as well as my Cygwin shell, it’s possible. I even fired up my Ubuntu Linux VM and tried it in the Terminal there, as well, and as expected, it works there too.

The cd alias in Windows PowerShell (that’s 5.1), which resolves to the Set-Location cmdlet, doesn’t do the same thing. Therefore, I made a quick modification to the Set-Location function I keep in my $PROFILE script. I’ll include it below, and then discuss it.

# Set-Location runs Push-Location, creates cd <blank> to $HOME (~).
Function Set-Location {
    Param (
        [string]$Path
    )

    If ($Path) {
        Push-Location -Path $Path
    } Else {
        Push-Location -Path ~
    }
}

My Set-Location function, just like the original cmdlet, accepts a path in order to know where in the file system to move the user. If the function is invoked without a path, however, it’ll now move the user to their $HOME directory (C:\Users\<username>\). So you’re aware, Push-Location puts the current location on the stack and then changes location to that which was specified. Again, it’ll move to $HOME, or ~, or C:\Users\<username>, which are all the same, if nothing is specified for the path parameter.

Here’s the a small portion of the help notes from the Push-Location cmdlet: “The Push-Location cmdlet adds, or pushes, the current location onto a location stack. If you specify a path, this cmdlet pushes the current location onto a location stack and then changes the current location to the location specified by the path.” Using my Set-Location function allows me to always use Pop-Location, or the popd alias, to return to my previous location in the file system.

In closing, I do want to mention that using cd by itself in PowerShell 6.0.2 on Windows, and PowerShell 6.0.0-alpha on Linux, works just like it does in Git Bash, Cygwin, and the Terminal on Ubuntu. Without an argument, it’ll automatically move you to your home directory, just like it does now, in my, Windows PowerShell 5.1.

Someone was paying attention.

The Pester Book Chapter Review (7)

Table of Contents – It Blocks

Today, we’ll review some of what was offered by the It Blocks chapter. Things, are getting interesting.

It turns out that It blocks are our main unit for testing. These blocks are the smallest blocks and belong inside a Describe and/or any Context blocks, if you’re using those. As they’re the smallest, it’s always best to keep them “simple, and as straightforward as possible.” The idea was that we should test everything independently of each other when we can, and that when we can’t, there needs to be a good idea as to why. That lead me to this write this Tweet today, where I questioned whether I should test all the permitted random password length values (4 – 35), that my random password function would accept in a single test, or one test — one It block — per value from 4 – 35. Take a look and let me know what you think as I’ve done both below. I haven’t actually seen any replies yet besides a few likes, and I still don’t know which I’ll end up using.

We also learned to have your It block throw a terminating error if an expectation isn’t met, the five possible results of an It block (passed, failed, etc.), using the Pending and Skip parameters on our It blocks, and finally about the Set-TestInconclusive option for It blocks that ensure a test is never run, under any circumstance.

Next we’re talking about Should. That should be interesting.

The Pester Book Chapter Review (6)

Table of Contents – Before and After Blocks

If for some reason you’re just getting here now, we’re doing chapter reviews on Adam Bertram‘s The Pester Book. Get a copy, start reading, and follow along with us. It’s the PowerShell testing framework, and you’re going to need to know it, if knowing PowerShell is something you already need to know.

Today we’re going to review a good, but short chapter on Before and After blocks. Before and After blocks contain two blocks each. Those are BeforeAll and BeforeEach, and AfterAll, and AfterEach.

BeforeAll and AfterAll blocks indicate things that should happen before any of the It blocks run, and after all the It blocks run, respectively. The difference with BeforeEach and AfterEach, is that whatever arbitrary code runs in these, does so before and after each It block, and not just once at the beginning and once at the end of a Describe and/or Context block.

Got it.

Linux Prompt on Windows – Part VII

Notes: There have been updates to this post since it was first published. See those notes near the bottom of the post.

There no huge changes between the most current version of my Linux prompt and this one, but it has changed. Because of that, I’ve decided a new post is in order. All the other related posts are linked below.

I took a brief look, and here’s what’s changed between this version and the last.

– There’s a $CustomPrompt variable. You can manually set this to either “real” or “fake.” If it’s “real,” it’ll use the true user and computer name in the prompt. If it’s “fake,” it will allow you to use your own fake user and computer name. In this case, it’ll use whatever has been assigned to the $UserComputer variable. Enter the fake user and computer name as <username>@<computername>. As you can see in the code, it currently says tommymaynard@cpux1789. I tend to use this for demos and screen captures where I don’t want my true username and computer name included.

– The other update here was a modification to the version number. Previously we’d have 2.0, 5.1, and 6.0 at the end of our prompt, and in the WindowTitle. Since the release of 6.0.2, the prompt now includes the first digit of the build, or patch number (it was changed to patch in 6.0). The WindowTitle, however, will include the full patch, or build number. Take a look at this screen capture.

I get the feeling someone might see all this code and think the prompt will load too slowly. It doesn’t. But as proof, I’ve included a quick Gif of the prompt in action. Maybe it’s slower than it should be, but even if it is, I bet you can’t tell. Each time a new prompt appears (Enter key is pressed), the below prompt function code has executed. Yeah, it’s not slow, so no worries on the prompt function length (60ish lines).

And without wasting any more of your time, here’s the prompt code. Drop it into your $PROFILE .ps1 file and give it a run. Like me, you just might find out you want it everywhere.

https://gist.github.com/tommymaynard/7f5907c9a4952a7f77b02c85801d3653

Update I: After posting my prompt function, I noticed something that didn’t make sense any longer. The variable assignment of $UserComputer was outside of the real/fake If-ElseIf statement. Therefore, that assignment was moved into the If portion, as it only needs to be set if the prompt is going to use the the real username and computer name.

Update II: I grew tired of the mid function $CustomPrompt variable assignment, and instead opted for a Type parameter that took care of this assignment. While you can’t pass the parameter value at run time, it’s better than burying the variable assignment deep in the prompt. Due to this, there were a few changes that had to be made to the If and ElseIf conditions. This was nothing more that changing $CustomPrompt to $Type (the newly added parameter).

Update III: Yes, another update (to the above code). Previously the switch statement that determined the host for the WindowTitle didn’t have a default value. That’s to say that if you were using a host other than the ConsoleHost, the Windows PowerShell ISE Host, or the Visual Studio Code Host, it would enter nothing in the WindowTitle before the PowerShell version number. Now, it’ll enter $Host.Name… whatever that ends up being.

Update IV: I removed my code and embedded the GitHub Gist where I’ve been keeping my prompt (outside of my $PROFILE script, of course).

Part VI | Part V | Part IV | Part III | Part II | Part I

The Pester Book Chapter Review (5)

Table of Contents – Describe Blocks

And, here we go. It’s time, to start testing with Pester. Or rather, it’s time to really start making our way toward that end goal. We’re going to start that with Describe blocks, also known as, “…the outer container for a group of tests.” It’s how this whole testing thing begins, and it looks like this:

Describe {

}

As stated, we need to think of a Describe block as a single shared scope for everything it contains. This means that the TestDrive PSDrive is available to all the tests within the Describe block. But what’s the TestDrive, right? I think it may have been mentioned previously, but it’s a drive — a PSDrive — that exists while the Describe block is executing. It’s a place to safely create folders and files during testing without the fear of making any mistakes against actual files and folders. There was also a mention of Mocks only existing while the Describe was running; I suspect we’ll get to these in time.

This chapter also touched on a few other valuable concepts that we’re going to be grateful we’ve learned. These included tagging. The Describe keyword actually has a Tag parameter that can be used to help separate whether, or not, a Describe block will run when using the Invoke-Pester function — don’t think we’ve talked about that one yet. Do keep in mind that if you don’t include a tag for a Describe block, that it’s always going to execute when the test is run.

This chapter also clued us in to upcoming topics, which included the Context block, It blocks, and BeforeAll, BeforeEach, AfterAll, and AfterEach. Keep reading; I’m about to do the same.

Add Measure-Command into a Function

During an at work demonstration of my Advanced Function Template recently, I heard an interesting idea from a teammate. It all started when I mentioned how many lines of code my function template required, without having even added any non template code to it. In version 1.0, the template required around 75 lines, which felt high. In subsequent versions it crept up past 100 — maybe 120. That also felt high, until I ran some tests and stopped caring. It’s probably past 120 by now, but I’ve stopped paying attention, as it no longer matters to me.

In my testing, a function that includes only a single string has an execution time of around 5,000 ticks. With 10,000 ticks per millisecond, you’re right to think that’s fast. With my most current version of the Advanced Function Template, with no additional code, it comes in at 3 – 4 milliseconds. Personally, I can’t tell the difference between a 1/2 of a millisecond and a few, and so the number of lines required by the template stopped meaning much to me. Especially since it only includes relevant and necessary code anyway. It’s worth it, especially since we now have region support in Visual Studio Code and can collapse any code we don’t want to have to constantly view anyway.

The interesting idea that was brought up, was to add a way to measure the execution of the Advanced Function Template (and its included, user based code [once that’s been added]), from within the function that’s been built using the template itself. I had never thought of such a thing. This is to say, wrap the Measure-Command cmdlet inside the template, in order to be able to run it against itself. If that’s confusing, no worries, the following code example should help explain.

Function Get-TheAlias {
    [CmdletBinding()]
    Param (
        [string]$Definition,
        [switch]$Measure
    )
    
    If ($Measure) {
        [System.Void]($PSBoundParameters.Remove('Measure'))
        Measure-Command -Expression {Get-TheAlias @PSBoundParameters}
    } Else {
        Get-Alias @PSBoundParameters
    }
}

The first two below examples do not use the Measure switch parameter offered in the above function. Therefore, they’ll head down the Else path of the If-Else statement. The first example will internally run Get-Alias with no parameters or parameter values (not all results are displayed). The second example also uses Get-Alias internally, however, it does so using the Definition parameter and a parameter value. The Definition parameter allows us to determine if there’s an alias, or aliases, for the given cmdlet or function. As there is, an alias for Get-Command is displayed.

PS > Get-TheAlias

CommandType     Name                                Version    Source
-----------     ----                                -------    ------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ?: -> Invoke-Ternary                3.2.0.0    Pscx
Alias           ?? -> Invoke-NullCoalescing         3.2.0.0    Pscx
Alias           ac -> Add-Content
Alias           And -> GherkinStep                  4.1.0      Pester
...
Alias           gwmi -> Get-WmiObject
Alias           h -> Get-History
Alias           hib -> Suspend-Computer
Alias           hibernate -> Suspend-Computer
Alias           history -> Get-History
Alias           i -> powershell_ise.exe

PS > Get-TheAlias -Definition Get-Command

CommandType     Name                                Version    Source
-----------     ----                                -------    ------
Alias           gcm -> Get-Command

The next two examples of the Get-TheAlias function do use the Measure parameter. In the first example, we only use the Measure parameter. Because the code dictates, we’ll head down the If portion of our If-Else language construct. It will strip the Measure parameter, and then measure the time it take to run a second, internal instance* of the Get-TheAlias function (which again, simply runs Get-Alias). When we also include the Definition parameter and a value, we’ll again strip the Measure parameter, and internally run a measured copy of Get-TheAlias function. This will again, execute Get-Alias with the Definition parameter and the submitted parameter value.

* Update: I do want to mention here, that there’s really no internal instance of the function. When a function calls itself, it looks for the function in it’s own scope (the child scope, inside the function). When it cannot be located there, it goes upward, to the parent scope, where it will find the declared function. Maybe this helps.

PS > Get-TheAlias -Measure

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 6681
TotalDays         : 1.75694444444444E-08
TotalHours        : 4.21666666666667E-07
TotalMinutes      : 2.53E-05
TotalSeconds      : 0.001518
TotalMilliseconds : 1.518

PS > Get-TheAlias -Definition Get-Command -Measure

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 1
Ticks             : 10287
TotalDays         : 7.28819444444444E-09
TotalHours        : 1.74916666666667E-07
TotalMinutes      : 1.0495E-05
TotalSeconds      : 0.0006297
TotalMilliseconds : 0.6297

It’s weird and different sure, but most of all, I need some thoughts on whether or not this will actually work long term. In my mind it does. It tries to run a function from its own function scope, when it can find that function, it goes up to the global scope and runs itself without the measure switch parameter. Sorry, if you’re still confused, but I’m finding it difficult to be 100% pleased with my ability to describe things.

If you’re not confused by this, then walk thought the function a time or two in your own head, or maybe even on a computer! Can you create or think of scenarios where adding a way to measure how long a function takes to complete can’t, or shouldn’t, be added to itself?

The Pester Book Chapter Review (4)

Table of Contents – Designing for Testing

In this chapter, we learned that Pester is going to make some assumptions about the code that we write. Therefore, in my mind, it’s going to be best if we learn what Pester is expecting and do that — well, those of us reading The Pester Book, at least.

This means we need to work with .ps1 files and functions, send our function output to the pipeline — good info — and that the results of our functions are consistent. Makes sense, right? If we’re testing that the value should be 5, then it’s not helpful if our code sometimes produces a random 6 (and there’s no test for that). This was actually better stated by Adam, when he wrote, “…for a given input, you get the same output.” His further elaborations were quite good, as well. As someone that uses iBooks and the ePub version, I highlighted a decent amount of the additional explanation.

Moving on, the book discussed that Pester would prefer that input be via parameters. If you’re not there yet, then get there, and stop settling for hard coded values, Read-Host prompts, or a function’s ability to read from the global scope when it can’t find what it wants in its current scope. If you’re not writing in functions — and this is really what this is about — then get there too. I spent a few posts before I started The Pester Book reviews trying to provide reasons why someone would want to do this (outside the community saying you should). It really does make your PowerShell life easier.

The chapter continues on by discussing output (think objects), that actions aren’t output (it makes sense when you read it), and finally, to keep commands as scoped as possible, as they’re easiest to test that way. This can be tough to teach, because people think whole project when they should be thinking task. But seriously, write in functions only, and keep them to a single purpose. Next, we’ll be back with a chapter on Describe Blocks.

This is getting good… I’ve done some Pester authoring previously, but I’ve never been taught it, so I’m looking forward to all those things I’m doing wrong, or didn’t know, because I didn’t give myself a complete training. Well, that’s the purpose of the book. Again, Describe blocks in our next review.

The Pester Book Chapter Review (3)

Table of Contents – Pester Concepts

As of this post, I’ve marched head first into Part I of The Pester Book.

It was a short chapter, as it included brief explanations of some Pester Concepts we’ll likely be spending more time with in our future. It explained Tests, as the basic unit of work within Pester. Remember, we’re on our way to learn how to test our PowerShell code with Pester. It also briefly touched on Mocks. This concept allows us to fake dependencies. The example used Get-Content. Instead of needing files from which we’d actually get the content, we can use mocking and have it appear as though we’ve returned the results we want, with the Get-Content cmdlet.

The chapter also included a brief discussion on assertions. It indicated that assertions are a core component of Pester (making a mental note of that). Assertions allow us to compare what should happen, and what does happen, when a specific part of our PowerShell executes.

Next, The Pester Book discussed scaffolding, and TestDrive. Scaffolding is referred to as a starting point for your tests. What it really seemed to be getting at, was the TDD philosophy. That’s the Test-Driven Development philosophy where you write (failing) tests first, then write the code to correct the tests. Without code in which to run your tests against, they’re going to fail, until you write the code that make those tests pass.

TestDrive is awesome. Or at first glance, it sounds like it will be. The TestDrive, drive is a FileSystem drive (like the C:\, D:\, etc.) that becomes available when a Pester test is running. This allows us to have a place to create file system objects while a Pester test is running, without worrying about negatively impacting a true filesystem where we don’t want to make changes.

This is getting good. Back soon.

The Pester Book Chapter Review (2)

Table of Contents – Introduction

As a reminder, as this is only the second post in this series, we’re about to begin a chapter review on The Pester Book. I would encourage you to get yourself a copy, if you haven’t already. Read your copy along with me and mine, and then head back here for chapter reviews. As mentioned once thus far, I’m not out to teach you Pester per se. That’s what the book is intended to do. Instead, I’m going emphasize the main points of each of the chapters. I’m going to write as though we’re reading the same thing at the same time. I have no idea if it’ll work, but I was confident enough. If you’re not reading along now, then use it when you are, or use it motivate yourself to do it at some time. Just don’t waste too much time, telling yourself you’ll eventually learn it.

I recently finished reading the Table of Contents through the Introduction and the introduction’s various parts. This means that I’ve covered the up front information — the about the author stuff, the foreword, how annoying code samples can be in “print,” and how to provide feedback. I’m actually appreciative that Adam’s willing to hear from the community about typos, code problems, and the like. As this is forever book, or living document, if you will, we can each be a part of ensuring its accuracy.

As you’ve seen, if you’re reading along, the book is broken down into five parts. These include Meet Pester, Using Pester, Using Gherkin with Pester, Code Coverage, and Pester Cookbook. Each part has anywhere from a single included chapter to several. These are pieces we’ll cover together, no matter how simple and short, or involved. I’m very grateful for the upfront, hey-let-me-introduce-you-to-Pester section. I get the feeling, the book isn’t out to make any assumptions that anyone of us already knows a portion of this content, even if we might.

I also get that same feeling from those introduction sections. The book briefly discusses the differences between unit tests, integration tests, regression tests, and the occasional acceptance test. Right off the bat, we’re getting a break down of the testing structure and type, and their logical order. It’s enough to get you excited to continuing reading; it was me, anyway. Now, it’s just me putting it to memory: unit, integration, regression, and acceptance.

As mentioned, testing isn’t new, but it may be to (some of) us. The whole Windows administrator turned scripting experts is still somewhat new on the Windows end. For me, I loved VBScript, back before PowerShell was even a thing. Back then, things were different though. You didn’t have to know VBScript to be a Windows system administrator. But now, you really should know PowerShell, and if you’re going to have to learn it and write it, then let’s learn to test it, too. Pester is going to be one of those things, that in time, people will assume you know, if you know PowerShell. That’s my prediction, anyway.

Before I wrap up here, I do want to mention the four paragraphs about testing that were included toward the end of the introduction. Those were highlighted as Testing as Institutional Memory, Testing Drives Better Modularization, Tests as Functional Specifications, and Test in Automated Build Pipelines. All very simple and short, yet important and relatable. See you again next time.