Книга: Getting Started with Pester 5
На главную: Предисловие
Дальше: Introduction to Templates in Pester

Getting Started with

Pester 5

A Beginner’s Guide

Owen Heaume

Getting Started with Pester 5: A Beginner’s Guide

Owen Heaume

West Sussex, UK

ISBN-13 (pbk): 979-8-8688-0305-5

ISBN-13 (electronic): 979-8-8688-0306-2

Copyright © 2024 by Owen Heaume

This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed.

Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.

The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to proprietary rights.

While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or omissions that may be made. The publisher makes no warranty, express or implied, with respect to the material contained herein.

Managing Director, Apress Media LLC: Welmoed Spahr

Acquisitions Editor: Smriti Srivastava

Development Editor: Laura Berendson

Editorial Assistant: Kripa Joseph

Cover designed by eStudioCalamar

Cover image designed by Cover image from Pixabay

Distributed to the book trade worldwide by Springer Science+Business Media New York, 1

New York Plaza, Suite 4600, New York, NY 10004-1562, USA. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail [email protected], or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation.

For information on translations, please e-mail [email protected]; for reprint, paperback, or audio rights, please e-mail [email protected].

Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales web page at http://www.apress.com/bulk-sales.

Any source code or other supplementary material referenced by the author in this book is available to readers on GitHub. For more detailed information, please visit https://www.apress.

com/gp/services/source-code.

If disposing of this product, please recycle the paper

Table of Contents

About the Author ���������������������������������������������������������������������������������xi About the Technical Reviewer �����������������������������������������������������������xiii Chapter 1:

Chapter 2:

iii

Table of ConTenTs

Chapter 3:

Chapter 4:

iv

Table of ConTenTs

Chapter 5:

Chapter 6:

v

Table of ConTenTs

Chapter 7:

Chapter 8:

Chapter 9:

vi

Table of ConTenTs

vii

Table of ConTenTs

viii

Table of ConTenTs

Index �������������������������������������������������������������������������������������������������245

ix

About the Author

Owen Heaume is a seasoned PowerShell

programmer with a passion for crafting

efficient solutions in the dynamic landscapes

of Intune and Azure. Having recently

embarked on a professional journey in

PowerShell programming for a prominent

company within their automation team, Owen

is dedicated to mastering the intricacies of

Pester, Azure DevOps, and adhering to best

practices.

Owen has published books on deploying

applications in Intune using PowerShell,

deploying applications in ConfigMgr using PowerShell, and deploying

language and regional settings using ConfigMgr. In this book, Owen

shares insights gained from real-world experiences, providing readers

with practical knowledge and a glimpse into the mind of a multifaceted professional thriving in the realms of technology.

xi

About the Technical Reviewer

Kasam Shaikh is a prominent figure in

India’s artificial intelligence (AI) landscape,

holding the distinction of being one of the

country’s first four Microsoft Most Valuable

Professionals (MVPs) in AI. Currently he

serves as a senior architect. Kasam boasts an

impressive track record as an author, having

authored five best-selling books dedicated to

Azure and AI technologies. Beyond his writing

endeavors, Kasam is recognized as a Microsoft

Certified Trainer (MCT) and an influential

tech YouTuber (@mekasamshaikh). He also leads the largest online Azure AI community, known as DearAzure | Azure INDIA, and is a globally

renowned AI speaker. His commitment to knowledge sharing extends to

contributions to Microsoft Learn, where he plays a pivotal role.

Within the realm of AI, Kasam is a respected subject matter expert

(SME) in generative AI for the cloud, complementing his role as a senior cloud architect. He actively promotes the adoption of No Code and Azure OpenAI solutions and possesses a strong foundation in Hybrid and

Cross-Cloud practices. Kasam Shaikh’s versatility and expertise make

him an invaluable asset in the rapidly evolving landscape of technology, contributing significantly to the advancement of Azure and AI.

xiii

abouT The TeChniCal RevieweR

In summary, Kasam Shaikh is a multifaceted professional who

excels in both technical expertise and knowledge dissemination. His

contributions span writing, training, community leadership, public

speaking, and architecture, establishing him as a true luminary in

the world of Azure and AI. Kasam was recently awarded as top voice

in AI by LinkedIn, making him the sole exclusive Indian professional

acknowledged by both Microsoft and LinkedIn for his contributions to the world of artificial intelligence!

xiv

CHAPTER 1

Unveiling the Power

of Pester

Welcome to the exciting world of Pester! In this chapter, we will embark on a journey to demystify the art of testing in PowerShell using the powerful tool called Pester. If you are new to PowerShell or testing frameworks, fear not; this guide is designed especially for you. Pester is not just any testing framework – it’s your key to ensuring your PowerShell scripts are robust, reliable, and perform exactly as you intend.

In the upcoming sections, we will unravel the fundamentals of Pester.

We’ll begin by understanding what Pester is and why it holds a crucial place in the toolkit of every PowerShell developer. You’ll learn about the compelling reasons to incorporate Pester into your scripting workflow, empowering you to write code with confidence.

We’ll guide you through the installation process, ensuring you have the latest version of Pester ready to use.

But our exploration doesn’t conclude there. In this chapter, we’ll

introduce you to the diverse spectrum of testing: unit tests, acceptance tests, and integration tests. These tests, much like different roles in a theatrical script, serve distinct purposes. Just as a director carefully selects actors for different scenes, you’ll learn to choose the right test type for various scenarios in your coding journey. Whether you’re validating

individual components, interacting with real systems, or staging integrated functions, you’ll have the tools to script tests that match your specific needs.

© Owen Heaume 2024

1

O. Heaume, Getting Started with Pester 5

Chapter 1 Unveiling the power of pester

We’ll then navigate the intricate landscape of Pester files and their

structure. By understanding the anatomy of these files, you’ll lay a sturdy foundation for crafting well-organized and potent tests.

Whether you’re a novice stepping into the PowerShell realm or a

seasoned developer eager to refine your testing expertise, this chapter promises to furnish you with vital insights to kickstart your Pester journey.

What Is Pester?

Pester, in the realm of PowerShell, is not just a testing framework; it’s a game-changer. Imagine having a reliable assistant by your side, carefully checking your PowerShell scripts for errors, ensuring they perform as

expected, and providing you with the peace of mind that your code is

robust. That assistant is Pester.

At its core, Pester is a testing framework specifically tailored for

PowerShell. It’s designed to simplify the process of writing and running tests for your PowerShell scripts and functions. But it’s not just about spotting bugs; Pester encourages a mindset of proactive development.

With Pester, you can validate your code’s functionality, ensure it handles various scenarios, and confirm it responds correctly to different inputs.

Pester operates on a simple yet profound principle: automated

testing is your safety net. It allows you to write tests that mimic real-world interactions with your scripts. By simulating different usage

scenarios, input variations, and edge cases, you can be confident that your PowerShell code behaves as intended under diverse conditions.

Why Use Pester?

In the early days of my PowerShell journey, the notion of incorporating Pester into my workflow seemed like an unnecessary complication. I had already carefully crafted my scripts, ensuring they worked flawlessly on my 2

Chapter 1 Unveiling the power of pester

system. The prospect of investing more time in writing additional code for testing felt daunting. I questioned, “Why add this layer of complexity when my scripts were already running smoothly?”

What I didn’t realize then was that Pester isn’t just about finding bugs or ensuring basic functionality. It’s a powerful ally that elevates your scripts from functional to exceptional. Here’s why taking that initial step to embrace Pester can transform your PowerShell experience:

1. Automated assurance: Pester acts as your

automated quality control mechanism. It tirelessly

validates your code, freeing you from the burden of

manual testing. With Pester, you can be confident

that your scripts are always in top-notch condition,

no matter how many times you modify them.

2. Confidence in code changes: As your scripts

evolve, ensuring they remain stable becomes vital.

Pester empowers you to confidently refactor and

enhance your code. By running a suite of tests, you

can instantly identify if any recent changes have

unintended consequences, enabling you to catch

issues before they escalate.

3. Effective collaboration: Imagine sharing your

scripts with team members or contributors. Pester

ensures that your code behaves consistently across

different environments. It becomes the common

language that bridges the gap between developers,

fostering collaboration and collective progress.

4. Saves time in the long run: Initially, writing tests

might seem like an additional effort, but it’s an

investment that pays off over time. Detecting and

fixing issues early prevents potential disasters down

3

Chapter 1 Unveiling the power of pester

the line. The time saved by avoiding manual bug

hunting far outweighs the time spent crafting tests.

5. Quality documentation: Pester tests serve as living

documentation for your code. They provide clear

examples of how your functions and modules are meant

to be used. This documentation becomes invaluable,

especially when revisiting your own code after a

considerable time gap or when onboarding new team

members.

6. Proactive problem solving: Pester doesn’t just find

problems; it anticipates them. By simulating various

scenarios and inputs, you can proactively identify

potential weaknesses in your code. Addressing these

vulnerabilities before they manifest in real-world

usage enhances the resilience of your scripts.

In essence, Pester isn’t merely about testing; it’s about empowering your scripts to reach their full potential. The beauty of Pester lies in its seamless integration with PowerShell. If you’re already familiar with PowerShell, learning Pester is a natural next step in enhancing your scripting arsenal.

Embracing Pester equips you with the tools to create robust, reliable, and maintainable PowerShell solutions. So, take the plunge, invest a bit of time now, and watch your scripts shine in the long run. Pester isn’t just a testing framework; it’s your ticket to PowerShell excellence.

Installing Pester

Installing Pester is a straightforward process, ensuring you have a robust testing environment for your PowerShell scripts. Pester can be installed on any Windows computer with PowerShell version 3 or higher, although it’s advisable to use PowerShell version 5 or 7 for the best experience.

4

Chapter 1 Unveiling the power of pester

Microsoft recognized the power of Pester and included it by default in Windows 10 and 11. However, the default versions might not always be the latest, and updating them can be tricky. Here’s the recommended method to ensure you have the most up-to-date and easily maintainable version of Pester installed.

1. Removing the Preinstalled Version: If you’re

dealing with an older version of Pester, it’s best

to remove it completely. Run the following

script shown in Listintrative

PowerShell window.

Listing 1-1. Uninstalling legacy Pester

$module = "C:\Program Files

\WindowsPowerShell\Modules\Pester"

takeown /F $module /A /R

icacls $module /reset

icacls $module /grant "*S-1-5-32-544:F"

/inheritance:d /T

This script ensures the clean removal of the

preinstalled Pester version, leaving your system

ready for the latest installation.

2. Installing the Latest Version: With the old version

removed, installing the latest Pester version is a

breeze. Execute the following command in an

administrative PowerShell window:

Install-Module Pester -Force

5

Chapter 1 Unveiling the power of pester

This command fetches and installs the latest version of

Pester, ensuring you have the most advanced features

at your fingertips.

3. Easy Updates: Managing updates is now hassle-

free. To update Pester, simply run the following

command in an administrative PowerShell window:

Update-Module Pester

This one-liner keeps your Pester framework current,

incorporating any improvements or bug fixes seamlessly.

By following these steps, you ensure that Pester is not just installed on your system, but it’s the latest, most potent version, and ready to empower your PowerShell testing endeavors. Now, let’s dive into understanding

Pester’s file structure and its core components.

Navigating the Testing Landscape

in PowerShell: Test Types

Welcome to the realm of testing in PowerShell, where scripts transform into robust and dependable solutions. Developers fine-tune their scripts through a series of carefully planned tests, much like orchestrating a captivating theater performance. Understanding the diverse landscape

of testing methodologies is akin to exploring the varied techniques in the world of theater, each designed to bring out the best in a production.

In this section, we embark on a journey through the fundamental

pillars of testing: unit tests, acceptance tests, and integration tests. Each test type is a unique lens through which developers can scrutinize their code, ensuring it not only meets its functional requirements but also

weathers the challenges of real-world execution.

6

Chapter 1 Unveiling the power of pester

I’ll employ a theater analogy (throughout this book) alongside

conventional explanations to simplify the topic. Understanding these test types can be a bit overwhelming at first, so likening them to elements in a theater production might make the concepts more digestible.

Unit Tests

Unit tests focus on individual components or “units” of your code, typically functions or cmdlets. A unit test evaluates a specific piece of functionality in isolation. For example, if you have a function that converts lowercase text to uppercase, a unit test for this function would provide it with specific input and check if the output matches the expected result. The goal is to validate that the function performs as intended in various scenarios. Unit tests are isolated from the broader system and do not rely on external resources or dependencies.

The Analogy: Precision on Stage

Unit tests are the fundamental building blocks, akin to rehearsing scenes with precision in a theater production. Just as each actor and prop must be scrutinized for readiness and quality, unit tests meticulously examine individual components of your PowerShell script. These tests isolate

functions, methods, or cmdlets, subjecting them to rigorous evaluations to ensure they perform their designated tasks flawlessly.

Integration Tests

Integration tests assess the interactions between different components or systems within your script. In the context of PowerShell, integration tests frequently involve connecting to external resources, databases, APIs, or other modules.

7

Chapter 1 Unveiling the power of pester

Unlike unit tests, integration tests focus on how these components

collaborate and whether they work correctly when integrated. For

example, if your script communicates with a database, an integration test would verify that the script can successfully connect, retrieve data, and handle responses. Mocking, where certain components are simulated to

mimic real behavior, is often used in integration testing to isolate different parts of the system.

This book centers on both unit tests and integration tests, with a

dedicated exploration of mocking for our integration tests, a topic that will be covered in a later chapter.

The Analogy: Orchestrating Script Performances

Integration tests resonate with the orchestration of diverse roles in a theater production. In a play, actors collaborate to bring characters to life, each contributing a unique essence to the overall performance.

Similarly, integration tests explore how different components of your

script interact. Whether it’s connecting with databases, APIs, or external services, these tests ensure that the script functions seamlessly in a connected environment, much like the synergy required among actors for a compelling stage production.

Acceptance Tests

Acceptance tests evaluate the overall behavior of your script within the real system, simulating user interactions or system operations. Unlike unit tests, acceptance tests are less concerned with the internal logic of individual functions and more focused on the script’s end-to-end

functionality. These tests often deal with real-world scenarios, covering the entire application workflow. However, acceptance tests might not cover all edge cases, as their purpose is to validate general system behavior rather than specific conditions.

8

Chapter 1 Unveiling the power of pester

The Analogy: The Grand Stage Performance

Acceptance tests are the final act on stage, equivalent to presenting the complete play. Here, the entire script is performed, mirroring the way a theater production reaches the audience. These tests focus on the end-to-end functionality, mimicking real-world scenarios and user interactions.

Just as the audience evaluates a play based on its presentation,

engagement, and impact, acceptance tests gauge your script’s

performance, ensuring it satisfies user requirements and expectations.

Each type of test serves a specific purpose in ensuring the reliability of your PowerShell code. By employing a combination of unit tests to validate individual functions, acceptance tests to assess overall system behavior, and integration tests to test component interactions, you can create a robust testing strategy that thoroughly evaluates your scripts’ functionality and performance.

As we delve into the intricacies of each test type, remember that testing is not merely a quality assurance task; it’s a theatrical journey where developers refine their craft. So, prepare for a captivating exploration of PowerShell testing, where precision, completeness, and harmony are the guiding principles.

Pester Test Naming Convention

and File Structure

In the world of Pester, naming conventions and file structures are your allies. Pester operates under the assumption that any file ending with .tests.

ps1 is a test file – a convention we highly recommend adhering to. While it’s theoretically possible to alter this behavior, diving into such complexity is beyond the scope of this beginner’s guide.

Why does Pester have this preference? Because Pester adores

functions, and it challenges you to become a better coder by crafting

functions that perform singular tasks. Writing functions this way not only 9

Chapter 1 Unveiling the power of pester

aligns with PowerShell best practices but also makes your code highly

testable. Consider a function like Get-User. It deserves its own file, aptly named Get-User.ps1. Correspondingly, your Pester test for this function should be named Get-User.tests.ps1. This clean separation ensures clarity in your project structure.

However, the naming standard can be further enhanced for

differentiation. Adding a descriptor about the type of test being conducted is a common practice. For instance, if you’re writing unit tests for Get-User, your test file could be named Get-User.unit.tests.ps1. Similarly, for integration tests, it could be Get-User.integration.tests.ps1, and for acceptance tests, Get-User.acceptance.tests.ps1.

This categorization not only clarifies the test type but also enables

selective test execution – a topic we’ll explore later in this book.

Keeping your .tests files in the same directory as the code they are

testing is a wise choice. This organization fosters coherence and ensures that your tests are always in sync with your code. For example,

Get-User\

Get-User.ps1

Get-User.tests.ps1

If you’re working with modules, a structured approach within module-

related directories is advisable:

Get-User\

Get-User\Public\

Get-User.ps1

Get-User\Tests\

Get-User.tests.ps1

This modular arrangement facilitates a seamless workflow, making

your tests as integral a part of your project as the code they validate. As you progress through this guide, you’ll gain deeper insights into how such meticulous structuring can optimize your PowerShell projects.

10

Chapter 1 Unveiling the power of pester

Summary

In this introductory chapter, we delved into the fascinating world of Pester, the testing framework designed to empower PowerShell developers. We

embarked on a journey to demystify testing in PowerShell, exploring the essential concepts that underpin Pester’s functionality.

We began by understanding what Pester is and why it’s indispensable

for every PowerShell developer. Pester emerged as more than just a testing framework; it became the key to ensuring that PowerShell scripts are

robust, reliable, and precisely execute their intended tasks. By embracing Pester, you unlock the potential to write code with confidence, fostering a culture of reliability and efficiency.

The chapter continued by addressing various types of tests, each

serving a distinct purpose in the realm of software testing. We deciphered the nuances between unit tests, acceptance tests, and integration tests, employing a theatrical analogy to simplify these concepts.

Next, we navigated the intricacies of Pester files and their structures.

Understanding the anatomy of these files laid the groundwork for crafting well-organized and potent tests. We also explored Pester’s naming

conventions and file structures, emphasizing the importance of clear

categorization for different test types. This structuring ensures that tests are always in harmony with the code they validate.

This chapter provided a comprehensive foundation for the Pester

journey ahead. By comprehending the core concepts of Pester, including its purpose, types of tests, and file structures, you are equipped with the foundational knowledge required to harness the full potential of this

powerful testing framework.

In Chapter , we will focus on the key building blocks of Pester: Describe, Context, and It. These constructs provide the framework for structuring tests effectively, enabling us to validate different aspects of our scripts with precision. Let’s get cracking!

11

CHAPTER 2

Mastering Pester

Fundamentals

Welcome to the heart of Pester! In this chapter, we will delve deep

into the fundamental building blocks that empower Pester to work its

magic in the world of PowerShell testing. Understanding these core

elements – Describe, Context, It, BeforeAll, AfterAll, BeforeEach, and AfterEach – is akin to mastering the essential chords in music or the basic strokes in painting. They form the foundation upon which your Pester tests will stand strong and resilient.

We will demystify the structure and purpose of these elements, guiding you through their application. By the end of this chapter, you’ll not only comprehend the syntax and usage of Pester’s fundamental components

but also grasp their significance in crafting robust and reliable tests for your PowerShell scripts. So, let’s embark on this journey of mastering Pester fundamentals, where you will gain the skills needed to wield the testing power of Pester effectively.

Understanding Blocks in Pester

In the realm of Pester, every test script revolves around a fundamental structure comprising various special script blocks. Each of these blocks plays a specific role, some obligatory and others optional. Let’s start by unraveling the very cornerstone of a Pester test: the Describe block.

© Owen Heaume 2024

13

O. Heaume, Getting Started with Pester 5

Chapter 2 Mastering pester FundaMentals

Describe: The Pillar of Logical Organization

The Describe block stands as the foundational element, a compulsory presence in every Pester test. Its primary purpose is to encapsulate your tests within a coherent, logical group. Think of it as the opening act in a play, setting the stage for the performances to follow. This block fosters clarity and unity, making your tests not only functional but also visually organized.

Within the Describe block, you have the flexibility to nest other Describe blocks, although this practice is less common. Instead, there are more refined methods to create subgroups within your tests which we will explore shortly.

Furthermore, the Describe block can house any number of Context or It blocks, essential components we’ll also delve into shortly.

Syntax

Describe "Function Name" { }

Typically, the first Describe block encapsulates the name of the function being tested, offering a clear context for the ensuing tests. For instance,

Describe "Get-User" {

# Code continues here

}

Beyond its fundamental structure, the Describe block supports various parameters, some of which we’ll explore in more depth later in this book.

Understanding the nuances of the Describe block lays the foundation for well-organized and comprehensible Pester tests.

Next, we will uncover its sibling components – Context and It blocks – each adding a layer of specificity and detail to your tests.

14

Chapter 2 Mastering pester FundaMentals

Context: Adding Contextual Relevance

While Describe blocks create overarching categories, Context blocks add contextual relevance. They enable you to define specific scenarios within a Describe block. Think of a Context block as an act within the aforementioned play, breaking down the drama into distinct scenes.

Like the Describe block, it also supports several other parameters we’ll see later; however, unlike the Describe block, Context blocks are optional, and you can choose to use them or not. If you do use them, you can have any number of them nested within your Describe block.

Syntax

Context "Scenario Description" { }

Listinws how you might use Context blocks.

Listing 2-1. Using multiple Context blocks for added clarity Describe "Get-User" {

Context "When User Exists" {

# Tests for scenarios where user exists go here

}

Context "When User Doesn't Exist" {

# Tests for scenarios where user doesn't exist go here

}

}

It: Defining Specific Tests

At the heart of your Pester tests are the It blocks. These mandatory blocks define specific tests, encapsulating individual assertions about your code’s behavior. Each It block represents a unique test case, akin to pivotal moments within an act, providing detailed information about the unfolding drama.

15

Chapter 2 Mastering pester FundaMentals

Syntax

It "Specific Test Description" { }

Listintrates It blocks in action.

Listing 2-2. Each It block represents a test case for your code Describe "Get-User" {

Context "When User Exists" {

It "Should Retrieve User Information" {

# Specific test assertions go here

}

It "Should Return User's Full Name" {

# More test assertions go here

}

}

}

Understanding the roles of Describe, Context, and It blocks is akin to mastering the grammar of a language. With these foundational

elements, you can articulate precise, reliable, and informative tests for your PowerShell scripts. In the upcoming sections, we’ll explore these blocks in greater depth, unveiling their nuances and best practices. Let’s continue our exploration, building the expertise needed to wield the full power of Pester in your testing endeavors by looking at four other optional script blocks.

Setting the Stage with BeforeAll

In Pester, preparing the ground for your tests is crucial. That’s where the BeforeAll block steps in. This specialized script block acts as a backstage manager, ensuring everything is in order before the main performance

begins. Here’s a closer look at how it operates.

16

Chapter 2 Mastering pester FundaMentals

The nonmandatory BeforeAll block is designed to handle

preconditions necessary for your Describe or Context blocks. It executes once for the entire Describe or Context and runs only once, providing an efficient way to initialize essential elements for your tests.

The BeforeAll block can be used to set up anything your subsequent tests will require as a one-time operation, be that initializing variables to creating objects. Commonly, the BeforeAll block is used to import the function under scrutiny by dot sourcing it, setting the stage for subsequent tests. Here’s an example of its usage at different levels:

At the Container Level

BeforeAll {

# Dot source the function to be tested

}

Describe "Get-User" {

# Tests go here

}

At the Describe or Context Level

Describe "Get-User" {

BeforeAll {

# Set up specific conditions for this

# Describe or Context

$Name = "Owen"

}

It "Should Test Something" {

# Test using the initialized conditions

Get-User -Name $Name

}

}

17

Chapter 2 Mastering pester FundaMentals

In this way, the BeforeAll block acts as the backstage crew, ensuring a smooth performance for your tests by handling the necessary setup before the curtain rises.

Clearing the Stage with AfterAll

In the intricate theater of Pester testing, the performance isn’t truly over until the stage is spotless. Enter the AfterAll block, akin to the dedicated crew that tidies up after the grand spectacle. This nonmandatory

specialized script block ensures a seamless cleanup operation after all the tests have had their moment in the spotlight.

The AfterAll block is your backstage cleanup crew, responsible for removing any traces left behind after the tests have run their course. Just as the BeforeAll block sets the stage, the AfterAll block ensures that the stage is left pristine, ready for the next act. It executes once, after all the tests in the Describe or Context block have concluded, providing a singular opportunity to perform essential cleanup tasks.

Imagine this scenario: your tests create temporary files or databases to simulate real-world conditions. The BeforeAll block sets the scene, while the AfterAll block, much like a diligent cleaning crew, sweeps away these temporary constructs, leaving your system in a pristine state. Listing

shows an example of the AfterAll block in action.

Listing 2-3. The AfterAll block

BeforeAll {

# Code to set up resources for testing

New-Item -Path C:\Temp\TestFile.txt -ItemType File

}

Describe "Sample Test Suite" {

It "Should do something" {

# Test code

}

18

Chapter 2 Mastering pester FundaMentals

# More tests...

}

AfterAll {

# Code to clean up resources after testing

Remove-Item -Path C:\Temp\TestFile.txt -Force

}

In this scenario, the BeforeAll block stages the necessary resources, and the AfterAll block ensures a meticulous cleanup, even if some acts didn’t go as planned (i.e., some of the tests failed), leaving the testing environment as pristine as it was before the performance began. With the AfterAll block in place, your tests conclude with a flourish, leaving no trace of their existence behind.

Preparing the Ground with BeforeEach

When testing, consistency and reliability are paramount. The show must go on smoothly, regardless of the number of acts or performers. That’s where the BeforeEach block takes its cue, ensuring that every act is set up perfectly before it takes the stage. Let’s explore its crucial role in the Pester performance.

The BeforeEach block acts as the backstage crew of your tests,

diligently preparing the stage for each individual performance. It executes once before every It block within the current Context or Describe block.

Since It blocks are where the actual tests unfold, the BeforeEach block ensures that whatever is contained within its script block is executed right before each test. For example, if you have two It blocks within your Describe block, the BeforeEach block will execute twice, once for each It.

This block is commonly used to create prerequisites for the current

tests. Whether it’s initializing variables, setting up mock functions, or establishing connections, the BeforeEach block guarantees that each test starts on a level playing field, ensuring consistent and reliable outcomes.

19

Chapter 2 Mastering pester FundaMentals

Here’s an example of its implementation:

Describe "Testing Something" {

BeforeEach {

# Setup code here

}

It "should perform a specific task" {

# Test code here

}

It "should handle another task" {

# Test code here

}

}

BeforeEach executes before any block within the current block or any of its child blocks. To illustrate, consider Listine the BeforeEach block will run before “Test1,” “Test2,” and “Test3,” ensuring each one starts on a level playing field.

Listing 2-4. BeforeEach in Action

Describe "Scope Test" {

BeforeEach {

# Code for setting up the stage

Write-host "I run before each test"

}

It "test1" {

Write-Host "Test1"

}

20

Chapter 2 Mastering pester FundaMentals

Context "The Context block" {

It "Test2" {

Write-Host "Test2"

}

It "test3" {

Write-Host "Test3"

}

}

}

Running Listinesents the following output as shown in Figur

Figure 2-1. The Write-Host output runs before every test

In this way, the BeforeEach block ensures that each test begins its performance with the same meticulously prepared stage, leading to a

consistent and flawless Pester production.

21

Chapter 2 Mastering pester FundaMentals

Nurturing Cleanliness with AfterEach

In the world of testing, ensuring a pristine environment after every trial is as crucial as the test itself. Enter AfterEach, your trusted cleanup crew in the Pester theater. Just as BeforeEach sets the stage, AfterEach ensures that the stage is left spotless after each performance, providing a fresh start for every subsequent test.

Much like its counterpart BeforeEach, AfterEach possesses the same attributes and operates with similar precision. AfterEach diligently follows every individual test within its current block or any of its child blocks.

It’s akin to a diligent janitor, swiftly tidying up the aftermath of each test, ensuring no residue is left behind.

By cleaning up any resources or setups used during the tests,

AfterEach maintains the integrity of your testing environment. Imagine it as a backstage team ensuring that every prop is back in its place and every costume is neatly hung after each act.

Note like its counterpart, AfterAll, AfterEach will run even if a test fails, guaranteeing test cleanup!

Listintrates AfterEach via Write-Host statements to show the execution flow.

Listing 2-5. AfterEach will run after each test

Describe "Scope Test" {

AfterEach {

# Code for setting up the stage

Write-host "I run after each test"

}

22

Chapter 2 Mastering pester FundaMentals

It "test1" {

Write-Host "Test1"

}

Context "The Context block" {

It "Test2" {

Write-Host "Test2"

}

It "test3" {

Write-Host "Test3"

}

}

}

Running Listin results in the following output as shown in Figur

Figure 2-2. The results of AfterEach

In the grand play of testing, AfterEach ensures that the stage is reset to its original state, ready for the next captivating performance.

23

Chapter 2 Mastering pester FundaMentals

Summary

In this chapter, we navigated through the foundational elements that

empower Pester. These essential building blocks, including Describe,

Context, It, BeforeAll, AfterAll, BeforeEach, and AfterEach, serve as

the fundamental chords in the symphony of Pester, forming the robust

foundation for crafting reliable tests.

We unraveled the structure and purpose of each element, emphasizing

their significance in creating tests for PowerShell scripts. By the chapter’s end, readers not only gained a comprehensive understanding of the syntax and usage of these components but also grasped their role in building

resilient and effective tests.

The chapter commenced with a focus on the Describe block, the

pillar of logical organization in Pester tests. Analogous to the opening act in a play, it sets the stage for performances by encapsulating tests within coherent, logical groups. We explored its syntax and nuances, laying the groundwork for the subsequent exploration of its siblings – Context and It blocks.

Context blocks were introduced as tools to add contextual relevance,

breaking down the drama into distinct scenes within a Describe block.

Their optional nature and ability to nest within Describe blocks were

highlighted, providing readers with a deeper understanding of their role in structuring tests.

The heart of Pester tests, the It block, was then spotlighted. As

mandatory components, It blocks define specific tests, encapsulating

individual assertions about code behavior. Each It block represents a

unique test case, contributing to the detailed narrative of the script’s performance.

Moving beyond these foundational elements, we explored four

optional script blocks – BeforeAll, AfterAll, BeforeEach, and AfterEach –

each playing a crucial role in orchestrating the testing performance.

24

Chapter 2 Mastering pester FundaMentals

BeforeAll, acting as the backstage manager, prepares the ground for

tests, executing once for the entire Describe or Context. It is a powerful tool for initializing essential elements for subsequent tests, ensuring a smooth performance.

AfterAll, the backstage cleanup crew, ensures a seamless cleanup

operation after all tests in the Describe or Context block have concluded. It removes any traces left behind, leaving the testing environment pristine for subsequent acts.

BeforeEach, likened to the backstage crew, diligently prepares the

stage for each individual performance. Executing before every It block within the current Context or Describe, it ensures consistent and reliable outcomes by setting up prerequisites for each test.

AfterEach, similar to BeforeEach, operates as a cleanup crew. It

maintains the integrity of the testing environment by swiftly tidying up after each test, ensuring a fresh start for subsequent performances.

With these fundamental elements and their detailed exploration,

readers are equipped to harness the full power of Pester in their testing endeavors. The chapter provided not only syntax insights but also practical examples, directing readers toward mastering the essentials of Pester.

Chaptwaits, guiding you through the practical aspects of Pester testing.

25

CHAPTER 3

Writing Your First

Tests

With a solid understanding of the fundamental concepts, it’s time to roll up your sleeves and start writing your first Pester tests. But before we dive into the practical aspects, let’s familiarize ourselves with some essential Pester cmdlets.

Pester Cmdlets

Pester, the PowerShell testing framework, features a collection of 28

cmdlets, including two aliases, as depicted in Figure . You will find yourself concentrating on approximately 13 or 14 of these cmdlets initially, streamlining the learning process. That’s under half the available cmdlets and very manageable!

© Owen Heaume 2024

27

O. Heaume, Getting Started with Pester 5

Chapter 3 Writing Your First tests

Figure 3-1. The available Pester cmdlets

To get a firm grip on their functionalities, I highly recommend

investing 10 minutes to explore the help documentation for each cmdlet.

You can do this by typing help <cmdlet> -full in a PowerShell window.

Although some of these cmdlets will be explored in later chapters, for now, let’s focus on three vital ones: It, Should, and Get-ShouldOperator.

28

Chapter 3 Writing Your First tests

It

The It command finds its home inside a Describe or Context block. If you’re well acquainted with the AAA pattern (Arrange-Act-Assert), (if not then do not fret – we will go over this shortly), the body of the It block is where assertions should be placed.

The convention here is to have one clear expectation per It block.

Any code inside the It block should throw a terminating error if the test’s expectation isn’t met, subsequently causing the test to fail. The name of the It block should explicitly express what the test is expecting.

The It block follows this structure:

It "tests something" { }

Should

In addition to creating your own logic for testing expectations and

throwing exceptions, Pester also provides the Should command, allowing you to perform assertions in plain language.

Should is a keyword specifically used to define assertions within an It block. It offers assertion methods to validate expectations, such as comparing objects. If an assertion isn’t met, the test fails, and an exception is thrown.

You can use Should multiple times within an It block if you have more than one assertion to verify. Each Should keyword should be on a separate line, and the test will only pass if all assertions are met.

Get-ShouldOperator

Get-ShouldOperator returns a list of available Should parameters, their aliases, and examples to help you craft the tests you need. Especially beneficial for beginners, you can leverage it as a convenient reminder of which parameters are permissible and which are not.

29

Chapter 3 Writing Your First tests

Figurws the output of Get-ShouldOperator.

Figure 3-2. A list of all the valid Should operators

30

Chapter 3 Writing Your First tests

This knowledge will lay a strong foundation for you to start crafting

your own Pester tests. Let’s move forward and put these concepts into

action using It, Should and a few should operators.

The Structure of a Test

At its core, a test comprises at least one Describe block and one It block, with the It block encapsulating the actual test logic. The fundamental syntax is demonstrated in Listing .

Listing 3-1. Basic test syntax

Describe "The function being tested" {

it "tests something" {

# The test goes here

}

}

To illustrate, let’s craft a sample test using a straightforward function, Get-Boolean (shown in Listing ). This function returns either true or false based on the supplied parameter.

Listing 3-2. The Get-Boolean function to be tested

function Get-Boolean {

param (

[ValidateSet ('True','False')]

$myBoolean

)

if ($myBoolean -eq 'True') {

$true

31

Chapter 3 Writing Your First tests

} else {

$false

}

}

Now, we can construct tests for this function, as demonstrated in

Listinith the test execution result shown in Figure .

Listing 3-3. Testing the function logic. It should return True Describe "Get-Boolean" {

it "returns true" {

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | should -BeTrue

}

}

Figure 3-3. The test result

Testing True and False Scenarios

To expand our test coverage for the Get-Boolean function, we can introduce additional tests to verify its behavior for both true and false scenarios. In Listing , two tests are implemented.

32

Chapter 3 Writing Your First tests

Listing 3-4. Adding another test

Describe "Get-Boolean" {

it "returns true" {

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | should -BeTrue

}

it "returns false" {

$expectedResult = Get-Boolean -myBoolean False

$expectedResult | should -BeFalse

}

}

In the first test, we ensure that the function returns true when provided with the parameter True. The $expectedResult is then piped to Should -BeTrue for assertion.

Conversely, the second test examines the behavior of the function

when the parameter is set to False. The expected result is piped to Should -BeFalse for verification. Figurws the test results.

Figure 3-4. The test results

33

Chapter 3 Writing Your First tests

By incorporating these tests, we establish a more comprehensive

examination of the Get-Boolean function, validating the function logic in both true and false scenarios. This approach aligns with the AAA pattern –

Arranging the test, Acting on the code, and Asserting the expected

outcome. As we progress, we’ll explore more complex scenarios and

assertions to fortify our testing practices.

The AAA Pattern: Arrange, Act, Assert

Adhering to a structured testing methodology enhances the clarity and

effectiveness of your tests. The AAA pattern – Arrange, Act, and Assert – is a widely adopted approach in writing meaningful and maintainable tests.

Arrange

In the Arrange phase, you set up the necessary preconditions for your test.

This includes initializing variables, defining inputs, and configuring the environment to mimic the conditions under which your code will run. This phase is crucial for isolating the specific functionality you want to test.

In the Listing , the creation of $expectedResult is part of the Arrange phase. Here, we’re preparing the context for the subsequent

action and assertion.

Listing 3-5. Arrange

Describe "Get-Boolean" {

It "returns true" {

# Arrange

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | Should -BeTrue

}

}

34

Chapter 3 Writing Your First tests

Act

The Act phase involves executing the specific functionality or code that you are testing. This is where you perform the actions that will produce the result you intend to evaluate as shown in Listin.

Listing 3-6. Act

Describe "Get-Boolean" {

It "returns true" {

# Arrange # Act

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | Should -BeTrue

}

}

The invocation of Get-Boolean -myBoolean True represents the Act phase. We are triggering the function with a specific input to observe its behavior.

Assert

The Assert phase is where you verify the outcome of the executed code. It checks whether the actual result aligns with the expected result. In Pester, this is often done using the Should command with various operators as demonstrated in Listing .

Listing 3-7. Assert

Describe "Get-Boolean" {

It "returns true" {

# Arrange # Act

$expectedResult = Get-Boolean -myBoolean True

35

Chapter 3 Writing Your First tests

# Assert

$expectedResult | Should -BeTrue

}

}

In this example, Should -BeTrue is the assertion, confirming that the result obtained in the Act phase meets our expectations.

Adopting the AAA pattern provides a systematic and clear structure to

your tests, making it easier to understand, maintain, and extend your test suite as your code evolves. To summarize AAA, let’s relate it to the theater analogy used throughout this book so far.

The AAA Theater: A Pester Production

Imagine your test scenario as a theatrical performance – an intricate play unfolding on the stage of your development environment. In this theatrical setting, the AAA pattern takes center stage as the director, orchestrating a flawless performance.

Act 1: Arrange – Setting the Stage

The curtain rises on the Arrange phase, where actors (variables and environment setup) take their positions on the stage. Props are arranged, costumes are donned, and the scene is meticulously prepared. This is the moment when the backstage crew ensures that everything is ready for the upcoming act.

Act 2: Act – The Main Performance

As the lights focus on the main stage, the Act phase commences. The lead actors (your code) step forward, delivering their lines and executing their roles. The plot unfolds as the code comes to life, performing the actions that will shape the narrative of your test.

36

Chapter 3 Writing Your First tests

Act 3: Assert – The Grand Finale

The grand finale arrives in the Assert phase, akin to the climactic scene of the play. The audience (your test suite) eagerly awaits the resolution. Did the actors (code) deliver the expected performance? The assert phase is the critical moment of truth, where the success or failure of the production is revealed.

Just as a well-orchestrated theater production requires seamless

coordination between the arrangement of actors, the execution of the play, and the final judgment of its success, the AAA pattern ensures a structured and effective performance in the theater of testing. Each act plays a vital role, contributing to the overall quality of the show. So, let the AAA Theater guide your testing endeavors, ensuring a standing ovation for your code.

A Glimpse into Should Operators

In our exploration of Pester’s Should command, the diverse array of operators, as showcased earlier in Figurght have caught your eye.

While many of them are quite intuitive, a few might benefit from a bit more clarification. Let’s delve into a couple of these operators.

-HaveParameter Operator

If your aim is to verify that your function boasts the expected parameters, then the -HaveParameter operator is your go-to. Consider our example function, Get-Boolean, which features a lone parameter, $MyBoolean.

To ensure this parameter persists and hasn’t undergone any unintended

alterations in future code revisions, we can employ PowerShell’s

Get-Command cmdlet, as illustrated in Listing .

37

Chapter 3 Writing Your First tests

Listing 3-8. Testing for parameters

Describe Get-Boolean {

It "Should contain the correct parameters" {

Get-Command Get-Boolean | Should -HaveParameter

"myBoolean"

}

}

In this snippet, we assert that our function contains the $MyBoolean parameter. Now, let’s unpack what’s happening here.

Explanation

1. Get-Command Get-Boolean: Utilizes the Get-

Command cmdlet to retrieve information about the

Get-Boolean function.

2. Should -HaveParameter “myBoolean”: Employs

the -HaveParameter operator to check whether

the function includes the specified parameter,

in this case, “myBoolean”. (Note the quotes

around myBoolean are optional, and there is no

preceding “$”.)

Note if you wish to check that the function parameter is mandatory, then add -Mandatory to the end of the assertion like so: Get-Command Get-Boolean | Should -HaveParameter

-Mandatory

38

Chapter 3 Writing Your First tests

What Have We Accomplished?

By crafting this test, we’ve established a validation mechanism to ensure that the critical parameter, $MyBoolean, is intact within our function.

This guards against accidental removal or renaming, contributing to

the robustness and reliability of our code. In the broader context of your testing arsenal, leveraging operators like -HaveParameter adds precision to your tests, safeguarding the integrity of your functions as they evolve over time.

-BeOfType Operator

As we navigate the realm of Pester’s Should command, the -BeOfType operator emerges as a valuable tool for verifying the type of object

returned by a function. This proves especially handy when you want to

ensure that your function delivers an object of a specific type, be it a string, a PSCustomObject, or another data type.

-BeOfType Operator in Action

Let’s apply this operator to our familiar companion, the Get-Boolean function, which we know yields a Boolean result. In Listing , we craft a test to confirm this expected outcome.

Listing 3-9. Should Operator -BeOfType

Describe Get-Boolean {

It " Should contain the correct parameters" {

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | Should -BeOfType Bool

}

}

39

Chapter 3 Writing Your First tests

Explanation

1. $expectedResult = Get-Boolean -myBoolean

True: Invokes the Get- Boolean function, capturing

its result in the $expectedResult variable.

2. $expectedResult | Should -BeOfType Bool: Uses

the -BeOfType operator to assert that the type of

the result stored in $expectedResult is indeed a

Boolean.

A Note on Syntax Following -BeOfType, you have flexibility in specifying the data type. in this instance, we use “Bool” to indicate

a Boolean type. alternatively, you could employ “Boolean,” “system.

Boolean,” or even “[system.Boolean]” – all achieving the same

validation.

What Have We Accomplished?

This test ensures that the Get-Boolean function adheres to its expected behavior by returning a result of the correct data type. Verifying the type of output becomes crucial as it adds an extra layer of certainty to the function’s performance. With -BeOfType and similar operators in your arsenal, you establish a robust defense against unexpected changes in

your code’s behavior. As our exploration advances, we’ll continue to

uncover additional operators that enhance the precision and reliability of your tests.

40

Chapter 3 Writing Your First tests

Running Your Tests

Writing tests is one thing, but executing them is the crucial next step in ensuring the reliability of your code. Let’s explore a couple of methods to set your tests in motion.

Inline Execution

The simplest method involves embedding your tests directly within the

script containing the functions under examination. In this approach, tests follow the functions they scrutinize, as demonstrated in Listing

Listing 3-10. Inline testing

function Get-Boolean {

param (

[ValidateSet ('True','False')]

$myBoolean

)

if ($myBoolean -eq 'True') {

$true

} else {

$false

}

}

Describe Get-Boolean {

It " Should contain the correct parameters" {

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | Should -BeOfType Bool

}

}

41

Chapter 3 Writing Your First tests

Dot Sourcing

Another strategy involves segregating each function into its individual file, such as MyFunction1.ps1 and MyFunction2.ps1. With dot sourcing, you

can then incorporate the functions and tests for execution, as illustrated in Listin

Listing 3-11. Dot sourcing the function

BeforeAll {

. $PSCommandPath.Replace('.Tests.ps1', '.ps1')

}

Describe Get-Boolean {

It " Should contain the correct parameters" {

$expectedResult = Get-Boolean -myBoolean True

$expectedResult | Should -BeOfType Bool

}

}

Decoding the BeforeAll Section

The BeforeAll block plays a pivotal role in the dot sourcing method.

Specifically, it ensures the execution of the script containing the functions before the tests commence. Here, $PSCommandPath comes into play, containing the full path and name of the script that is currently being run.

Of course, your .tests file needs to be located in the same directory as the function script being tested, or it won’t work.

In the context of Listinath is manipulated to replace

‘.Tests.ps1’ with ‘.ps1,’ ensuring that the correct script is sourced before the tests are initiated.

42

Chapter 3 Writing Your First tests

Feel free to dot source the functions any way you like if you prefer to use . $PSScriptRoot/myFunction.ps1 or a more long-winded method

then go ahead.

Caution ensure that you wrap the dot source command within the BeforeAll script block; otherwise, it won’t work.

If your function.ps1 file is in a different location to your .tests, you could still dot source it by explicitly naming the path like this:

BeforeAll {

$scriptPath = "C:\Path\To\Your\Script.ps1

. $scriptPath

}

This careful orchestration guarantees that the functions are

seamlessly integrated into the testing environment, setting the stage for comprehensive evaluations.

Import-Module

When working with PowerShell modules and aiming to test the functions

encapsulated within them, the process involves importing the module

before executing the tests. This method proves invaluable for assessing the behavior and correctness of functions within the modular structure of your scripts.

In the following example, presented in Listin, we showcase how to seamlessly import a module to facilitate testing. This becomes

particularly relevant when your script is organized into modular

components, and you want to test each function’s functionality

independently.

43

Chapter 3 Writing Your First tests

Listing 3-12. Importing the module before tests

BeforeAll {

$moduleName = 'yourModuleName'

Get-Module -Name $moduleName -All | Remove-Module -Force

$module = Get-Module -Name $moduleName -ListAvailable

Import-Module -Name $module -Force

}

Describe "A function in the module" {

It "tests something" {

# test code

}

}

Note it’s crucial to recognize that with this approach, you can exclusively test functions that have been exposed publicly by the

module. this won’t work for private functions, and we’ll address this

later in the book.

Decoding the BeforeAll Section

The BeforeAll block plays a crucial role in the process of importing modules. In this context, it ensures the designated module, identified by

‘yourModuleName,’ is removed and then imported before the tests begin.

This guarantees a clean slate for testing the specific module functions.

Integrating Testing into Your Workflow

By embracing different execution methods, you gain the flexibility to

seamlessly integrate testing into your development workflow. Whether

you opt for the straightforward approach of inline execution, leverage 44

Chapter 3 Writing Your First tests

the organizational advantages of dot sourcing, or harness the modular

structure by importing modules, the decision is entirely yours. Each

method caters to various preferences and project requirements.

Invoke the Magic

While it’s convenient to press the “play,” “execute,” or “Run Script” button in your chosen IDE to run tests, consider leveraging the power of the

Invoke-Pester command for a more insightful experience.

Executing tests through Invoke-Pester offers a deeper understanding of the various structures of your tests. For instance, if you opt for the traditional “run scripts” method or press F5 in the integrated Windows PowerShell IDE, you’ll receive an output similar to what’s shown in

Figur

Figure 3-5. Basic test output

However, using Invoke-Pester introduces a wealth of parameters, including the powerful -Output option. When set to “detailed,” this parameter transforms the output significantly, providing a more

comprehensive test analysis, as illustrated in Figure for the same set of tests.

45

Chapter 3 Writing Your First tests

Figure 3-6. Detailed output. Use the -Path parameter to point to the

.tests.ps1 file location

Now, you can visualize a detailed breakdown of the different blocks the tests have passed through.

In later chapters, we’ll delve into some of the other valuable

parameters offered by Invoke-Pester.

Summary

In this chapter, you embarked on the practical journey of writing your initial Pester tests, laying a foundation for robust and reliable PowerShell scripts. You explored essential Pester cmdlets, focusing on It, Should, and Get-ShouldOperator. The chapter delved into the fundamental structure of a test, featuring the Describe and It blocks, and illustrated the process with a sample test for the Get-Boolean function.

The AAA pattern – Arrange, Act, and Assert – emerged as a guiding

principle for structuring tests systematically. Through theatrical analogies, the chapter compared testing phases to a well-orchestrated play,

emphasizing the importance of setting the stage, executing the main

performance, and delivering a grand finale.

The introduction of two vital Should operators, -HaveParameter and

-BeOfType, added precision to your tests. You explored testing parameters’

existence and validating object types, enhancing the reliability of your scripts.

46

Chapter 3 Writing Your First tests

Execution methods, including inline execution, dot sourcing, and

module importing, were thoroughly examined. Each method was

explained, decoded, and contextualized within the broader framework of integrating testing into your development workflow.

Additionally, the chapter touched upon the power of Invoke-Pester,

providing a deeper insight into test structures and paving the way for a more comprehensive understanding of your script’s performance.

In Chapter , you will delve into the nuanced world of block scope within Pester. Understanding how variables and scopes behave in different blocks is crucial for writing effective and maintainable tests. As you master block scope in Pester, you’ll gain insights that elevate your testing practices, contributing to the overall excellence of your PowerShell scripts.

Get ready to enhance your skills and refine your testing prowess in the upcoming chapter!

47

CHAPTER 4

Mastering Block

Scope in Pester

As we journey through Pester testing, mastering the concept of block

scope is paramount for ensuring the accuracy and reliability of your tests.

This chapter delves deep into the intricacies of block scope, unraveling its nuances and clarifying its importance in Pester scripting. Through meticulous examination and hands-on exploration, we will navigate the

terrain of block scope, providing you with the insights and understanding necessary to craft robust and precise tests in Pester.

Defining Block Scope

Consider our illustrative function, Get-Greeting (Listinigned to greet users based on their names.

Listing 4-1. The function being tested

function Get-Greeting {

param (

[string]$Name

)

if ($name -eq "Owen") {

write-host "Hello $name" -ForegroundColor green

© Owen Heaume 2024

49

O. Heaume, Getting Started with Pester 5

Chapter 4 Mastering BloCk sCope in pester

return 5

} elseif ($name -eq "Judith") {

write-host "Hello, Judith" -ForegroundColor Cyan

return 6

} else {

write-host "Who are you?" -ForegroundColor Magenta

return 7

}

}

When testing this function with Pester (Listing ou encounter an issue: the variable $myvar, declared in the Arrange phase within the first It block, is invisible to subsequent blocks within the same context, causing a test failure.

Listing 4-2. The second test will fail

Describe "Get-Greeting" {

context "testing" {

It "Returns expected output" {

# Arrange

$myvar = 5

# Act

$expected = Get-Greeting -Name 'Owen'

# Assert

$expected | Should -Be $myvar

}

50

Chapter 4 Mastering BloCk sCope in pester

it "will fail" {

# Assert

$myvar | should -be 5

}

}

}

In Figurou can see the results of the Pester test – note the second test has failed.

Figure 4-1. The second test failed because of a scoping issue Elevating Scope with BeforeAll

To grant accessibility of $myvar to all It blocks within the context, you can employ the BeforeAll block, as demonstrated in Listing .

Importantly, BeforeAll will now apply to all child blocks of the context level, ensuring the smooth execution of tests and underscoring the

necessity of defining code elements at appropriate scope levels.

51

Chapter 4 Mastering BloCk sCope in pester

By defining BeforeAll at the Context level, any code elements within it become visible to all tests within that context.

Listing 4-3. Moving BeforeAll to the Context block

Describe "Get-Greeting" {

context "testing" {

BeforeAll {

$myvar = 5

}

It "Returns expected output" {

# Act

$expected = Get-Greeting -Name 'Owen'

# Assert

$expected | Should -Be $myvar

}

it "will pass" {

# Assert

$myvar | should -be 5

}

}

}

With the scope changed, the tests both pass as shown in Figur

52

Chapter 4 Mastering BloCk sCope in pester

Figure 4-2. All tests now pass

Note keen-eyed readers might have noticed the somewhat

unattractive inclusion of “hello owen” within the test output. Fear

not, for this less-than-ideal embellishment in the test results can be effortlessly addressed. Further insights into this matter will unfold in the forthcoming chapter dedicated to the art of mocking.

Contextual Hierarchies and Limitations

Navigating through different contexts reveals a crucial aspect of block scope: BeforeAll is inherited only by child scopes of its context. Listing

demonstrates this: the test within the second context block will fail.

Listing 4-4. Tests in the second Context block will fail Describe "Get-Greeting" {

context "testing" {

BeforeAll {

$myvar = 5

}

53

Chapter 4 Mastering BloCk sCope in pester

It "Returns expected output" {

# Act

$expected = Get-Greeting -Name 'Owen'

# Assert

$expected| Should -Be $myvar

}

it "will pass" {

# Assert

$myvar | should -be 5

}

}

Context "something else" {

it "will fail" {

# Assert

$myvar | should -be 5

}

}

}

In Figurou can see that the test within the second context block has failed.

54

Chapter 4 Mastering BloCk sCope in pester

Figure 4-3. Oh no – an unexpected test failure due to scope definition To broaden the variable's scope across all contexts, you move the

BeforeAll block to the parent scope, the Describe block, as shown in Listinow, every context (and its child blocks) within the Describe block has access to the top-level variables because the BeforeAll will apply to any and all child blocks of the Describe block.

Listing 4-5. BeforeAll has moved up a level. All tests now pass Describe "Get-Greeting" {

BeforeAll {

$myvar = 5

}

context "testing" {

It "Returns expected output" {

55

Chapter 4 Mastering BloCk sCope in pester

# Act

$expected = Get-Greeting -Name 'Owen'

# Assert

$expected | Should -Be $myvar

}

it "will pass" {

# Assert

$myvar | should -be 5

}

}

Context "something else" {

it "will pass" {

# Assert

$myvar | should -be 5

}

}

}

After shifting the scope up a level, the tests now pass as expected as shown in Figure .

56

Chapter 4 Mastering BloCk sCope in pester

Figure 4-4. The scope is in the Describe block and all tests pass The Perils of Unbounded Scope

Attempting to declare $myvar outside the allowed blocks as shown in Listinads to unexpected outcomes. All tests fail because $myvar has not been declared within a valid script block.

Listing 4-6. Doomed to failure

Describe "Get-Greeting" {

context "testing" {

$myvar = 5

It "will fail" {

# Act

$expected = Get-Greeting -Name 'Owen'

# Assert

$expected| Should -Be $myvar

}

57

Chapter 4 Mastering BloCk sCope in pester

it "will also fail" {

# Assert

$myvar | should -be 5

}

}

}

In the code examples for this chapter, we have been using BeforeAll although other blocks may be used. Your various code elements must be encapsulated within designated script blocks, such as It, BeforeAll, BeforeEach, AfterAll, or AfterEach. Straying from these guidelines results in unpredictable behavior, as shown in Figurphasizing the importance of adhering to specified scopes.

Figure 4-5. All your code elements must be encapsulated within a valid script block. In Listin , $myvar has been declared in the context block but is not within its own script block, such as BeforeAll or BeforeEach, causing all tests to fail

58

Chapter 4 Mastering BloCk sCope in pester

Our Ubiquitous Theater Analogy

In software testing, understanding block scope is akin to directing a

multifaceted stage production. Each script block – be it It, BeforeAll, BeforeEach, AfterAll, or AfterEach – represents a distinct act in the play.

Within these acts, variables, commands, and other testing elements

are performers, each playing a role crucial to the overall performance.

The director (tester) ensures that every element, from simple variables to complex commands, understands their place and purpose within their

designated acts.

Just as actors seamlessly transition between scenes, variables and

commands flow flawlessly from one block to another, creating a cohesive and impactful testing narrative.

This orchestration ensures that when the curtains rise (tests run),

the entire production unfolds with precision and effectiveness, leaving the audience (developers and stakeholders) in awe of the seamless

performance on the testing stage.

Summary

In this chapter, we delved into the critical concept of block scope within Pester testing. The chapter meticulously explored the nuances of block scope, clarifying its intricacies and highlighting its pivotal role in crafting accurate and reliable tests. Through hands-on exploration, we navigated the landscape of block scope, offering insights and understanding to

empower you in the creation of robust and precise Pester tests.

The journey began with the definition of block scope, using the

illustrative function Get-Greeting to demonstrate the challenges posed by variable scope within Pester. The chapter emphasized the importance of defining code elements at appropriate scope levels for smooth test

execution.

59

Chapter 4 Mastering BloCk sCope in pester

We explored the introduction of BeforeAll to elevate scope, ensuring

variables are accessible to all It blocks within a context. The contextual hierarchies and limitations were uncovered, emphasizing the inheritance of BeforeAll only by child scopes of its context. The solution was presented by moving the BeforeAll block to the parent scope, the Describe block.

The chapter highlighted the perils of unbounded scope, illustrating

the unexpected outcomes of declaring variables outside valid script

blocks. The importance of encapsulating code elements within designated script blocks, such as It, BeforeAll, BeforeEach, AfterAll, or AfterEach, was underscored for predictable behavior.

Finally, our ubiquitous theater analogy portrayed understanding block

scope as directing a multifaceted stage production. Each script block

represented a distinct act, and variables and commands played crucial

roles akin to performers. The director (tester) orchestrated a seamless flow of elements between acts, ensuring a cohesive and impactful testing narrative.

Next, in Chapter , we'll explore the efficiency of Pester's -ForEach parameter and delve into the world of data-driven testing, enhancing the scalability and readability of your Pester test suite.

60

CHAPTER 5

Data-Driven Tests

Efficiency in testing is not just about ensuring the functionality of

individual components but also about managing your testing suite

intelligently. As your PowerShell scripts evolve and diversify, you may encounter scenarios where numerous tests share a common structure or

objective. Writing these tests individually can be time-consuming and may lead to redundancy in your codebase.

Drawing inspiration from the principles of data-driven testing, this

chapter explores how to leverage the -ForEach parameter in Pester. We’ll guide you through its application, demonstrating how it enables you to create concise and maintainable tests. By the end of this chapter, you’ll not only understand the mechanics of -ForEach but also appreciate its role in enhancing the efficiency and readability of your Pester test suite.

Testing the Waters: Rigorous Evaluation

of Remove-Files Functionality

In the journey of mastering Pester, we encounter scenarios where a

function, like the illustrative Remove-Files in Listinecomes a pivotal element of our PowerShell arsenal. This function adeptly deletes files based on specified parameters, showcasing the functionality that we want to subject to rigorous testing.

© Owen Heaume 2024

61

O. Heaume, Getting Started with Pester 5

Chapter 5 Data-Driven tests

Listing 5-1. Remove-Files – our sample function

function Remove-Files {

param (

[ValidateSet ('txt', 'log', 'tmp')]

[string]$FileType,

[Parameter(Mandatory = $true)]

[string]$Path

)

switch ($FileType) {

'txt' { Remove-Item -Path $Path\*.txt -Force }

'log' { Remove-Item -Path $Path\*.log -Force }

'tmp' { Remove-Item -Path $Path\*.tmp -Force }

}

}

As diligent testers, we start by crafting tests for Remove-Files, as depicted in Listing . Each test focuses on a specific file type, ensuring our function behaves as expected.

Listing 5-2. Initial tests

Describe 'Remove-Files' {

Context 'when removing files from the specified path' {

It 'should remove all txt files' {

Remove-Files -FileType 'txt' -Path 'C:\Temp'

$files = Get-ChildItem -Path 'C:\Temp'

-Filter '*.txt'

$files | Should -BeNullOrEmpty

}

62

Chapter 5 Data-Driven tests

it 'should remove all log files' {

Remove-Files -FileType 'log' -Path 'C:\Temp'

$files = Get-ChildItem -Path 'C:\Temp'

-Filter '*.log'

$files | Should -BeNullOrEmpty

}

it 'should remove all tmp files' {

Remove-Files -FileType 'tmp' -Path 'C:\Temp'

$files = Get-ChildItem -Path 'C:\Temp'

-Filter '*.tmp'

$files | Should -BeNullOrEmpty

}

}

}

Warning it’s essential to be aware that executing Listing

would result in the deletion of files. We plan to address this scenario in a later chapter. Kindly refrain from running this in a production

environment or any environment where you want to keep your files!

Reviewing Chapter Insights with Listing

Before we proceed with adapting our test to embrace a data-driven

approach, let’s pause and reinforce our understanding of previous

chapters by dissecting the details of Listing .

63

Chapter 5 Data-Driven tests

Describe ‘Remove-Files’

This initiates a test suite or group named ‘Remove-Files’, providing a logical container for related tests.

Context ‘when removing files

from the specified path’

Within the ‘Remove-Files’ suite, there is a context defined. A context is a way to further organize tests within a suite based on specific scenarios or conditions. In this case, the context is ‘when removing files from the specified path’, indicating that the following tests will focus on the behavior of Remove-Files under this circumstance.

It ‘should remove all txt files’

Inside the context, there is an individual test defined using the It statement. This test checks the behavior of the Remove-Files function

when instructed to remove all ‘.txt’ files from the ‘C:\Temp’ path.

Remove-Files -FileType 'txt' -Path 'C:\Temp'

$files = Get-ChildItem -Path 'C:\Temp' -Filter '*.txt'

$files | Should -BeNullOrEmpty

1. Remove-Files -FileType ‘txt’ -Path ‘C:\Temp’:

This line calls the Remove-Files function with

the parameters set to delete ‘.txt’ files from the

specified path.

2. $files = Get-ChildItem -Path ‘C:\Temp’ -Filter

‘*.txt’: This line retrieves all ‘.txt’ files in the

‘C:\Temp’ directory and assigns them to the

variable $files.

64

Chapter 5 Data-Driven tests

3. $files | Should -BeNullOrEmpty: This line uses

the Pester Should statement to assert that the $files

variable should be null or empty. In other words,

it checks that all ‘.txt’ files have been successfully

removed.

The subsequent tests for log and tmp files follow a similar structure, each verifying that the corresponding file types are removed from the

Дальше: Introduction to Templates in Pester