Product and service reviews are conducted independently by our editorial team, but we sometimes make money when you click on links. Learn more.
 

How to Deal with Dependencies in Your Pester Infrastructure Tests

By - Source: Toms IT Pro

Infrastructure tests are different, and it's important to be aware of dependencies when doing so.

When writing Pester infrastructure tests, you'll cross a common problem; dealing with dependencies. This is because, unlike unit tests, infrastructure tests actually run real code and touch the real environment. And real environments are complicated and full of dependencies on compute, networking, storage, etc. To build a reliable and accurate infrastructure test, it's important to be cognizant of these dependencies and accounts for them in your tests.

What's a "dependency" anyway? A dependency can mean anything from a VM being provisioned, a folder that must be created before a file can be placed inside, a domain being available before adding an Active Directory user to it, etc. Thinking of dependencies in this way will make your head spin especially if thought of more granularly like what it takes to render a web page! You're going to have to make some tradeoffs.

MORE: How to Build a Pester Test Framework

For a simple example, I have some code that creates an Active Directory user. What must be in place before this task can be tested? Thinking from the closest dependency to the farthest way, we might need an organizational unit to place the user in, but we need a domain to put that OU in.

But wait, in order to have a domain, at least one server must be running Active Directory Domain Services (ADDS). ADDS requires a server to run. We need to ensure a VM or physical server is setup for that... Infrastructure dependencies can run deep, but at some point, you must assume some things.

In the upcoming example, I'm going to assume that I have a network in place and a server that's supposed to be a domain controller. Other than that, I'll be testing all other dependencies. In this case, I'll be checking to ensure that server is actually a domain controller and an OU is setup that we'll be placing the AD user in.

You'll need to have Pester installed on a machine and added as a member of the domain that the user would be created in. Also, for the test to run all the way through, ensure that the domain controller (DC) is online. This will prevent us from having to bring up a DC for every test run.

For this article, we're going to be testing infrastructure dependencies at the Pester describe block level. This means that in order for any tests to run, the environment must be in a preferred state. To do this, I define all of the variables to use in these dependency tests. For our example, I'll need the name of the domain controller and the name of the OU.
describe 'New-CompanyADUser' {
    
    $domainController = 'TESTDC'
    $ouPath = 'OU=CompanyUsers,DC=mylab,DC=local'
}

I created a file called New-CompanyADUser.Tests.ps1 and created a describe block that looks like the above example. Then I added the prerequisite checks. To add and remove multiple checks quickly, I created an array and defined each test as a scriptblock.
$conditions = @(
        @{Name = 'DC is online'; Action = { Test-Connection -ComputerName $domainController -Quiet -Count 1 }}
        @{Name = 'OU exists'; Action = { Invoke-Command -ComputerName $domainController -ScriptBlock { Get-AdOrganizationalUnit -Filter { Name -eq $using:ouPath }}}}
)

I can now run each of these checks by iterating over each with a foreach loop. Here I'm checking to see if each of the checks returns anything. If they return nothing or $false, the check will fail, and the test will fail before it even gets started.
@($conditions).foreach({
    if (-not (& $_.Action)) {
        throw "The dependency test [$($_.Name)] failed. Cancelling further tests."
    }
})

I ran the test while my required OU was not present.
Invoke-Pester -Path C:New-CompanyADUser.Tests.ps1

You can see that I received an important message about what dependency test failed and that a test failed. I created the required OU and see what happens.

This time no error was thrown, and no tests failed. If I had actual tests in this example, it would have shown pass/fail instances for each It block.

Wrap up

This was a simple example of infrastructure dependency checking with Pester. If necessary, this concept can be taken to the next level by creating dependencies on the fly. Or, if more granular checking is needed, the checks could be incorporated into the It blocks themselves by using the Set-TestInconclusive Pester command as well. This would ensure that if a dependency check failed, the test would not be labeled a pass/fail but be represented in an inconclusive state.

Comments