I use Pester 5.1.1 to test Azure Resources after their deployment.
In Azure DevOps Services I execute a PowerShell task within a pipeline that triggers one script (Start-Pester.ps1) which in turn invokes tests from another script (PostDeployment.Tests.ps1) while passing the necessary parameter values.
Start-Pester.ps1
param(
[string]$SubscriptionId,
[string]$TenantId,
[string]$Username,
[string]$Password,
[string]$ResourceGroupName,
[string]$FunctionAppName,
[string]$EventHubNamespaceName,
[string]$EventHubNamespaceAuthorizationRuleName,
[string]$EventHubName,
[string]$EventHubAuthorizationRuleName,
[string]$EventHubAuthorizationRuleName1,
[string]$ModulePath,
[switch]$Publish,
[string]$ResultsPath
)
[string]$SubscriptionId = (Get-Item env:SubscriptionId).value
[string]$TenantId = (Get-Item env:TenantId).value
[string]$Username = (Get-Item env:Username).value
[string]$Password = (Get-Item env:Password).value
[string]$ResourceGroupName = (Get-Item env:ResourceGroupName).value
[string]$FunctionAppName = (Get-Item env:FunctionAppName).value
[string]$EventHubNamespaceName = (Get-Item env:EventHubNamespaceName).value
[string]$EventHubNamespaceAuthorizationRuleName = (Get-Item env:EventHubNamespaceAuthorizationRuleName).value
[string]$EventHubName = (Get-Item env:EventHubName).value
[string]$EventHubAuthorizationRuleName = (Get-Item env:EventHubAuthorizationRuleName).value
[string]$EventHubAuthorizationRuleName1 = (Get-Item env:EventHubAuthorizationRuleName1).value
$WarningPreference = "SilentlyContinue"
Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "true"
[array]$ModuleName = @("Az.Accounts", "Az.Resources", "Az.EventHub", "Az.Functions")
foreach ($Module in $ModuleName) {
Install-Module $Module -Scope CurrentUser -Force -SkipPublisherCheck -confirm:$false -AllowClobber
Import-Module -Name $Module
Get-InstalledModule -Name $Module -AllVersions | Select-Object Name, Version
}
# Authentication
$Credentials = New-Object System.Management.Automation.PSCredential ($Username, $(ConvertTo-SecureString $Password -AsPlainText -Force))
Connect-AzAccount -Credential $Credentials -ServicePrincipal -Tenant $TenantId
# Subscription
Set-AzContext -Subscription $SubscriptionId
$PesterModule = Get-Module -Name Pester -ListAvailable | Where-Object { $_.Version -like '5.*' }
if (!$PesterModule) {
try {
Install-Module -Name Pester -Scope CurrentUser -Force -SkipPublisherCheck -MinimumVersion "5.0" -Repository PSGallery
$PesterModule = Get-Module -Name Pester -ListAvailable | Where-Object { $_.Version -like '5.*' }
}
catch {
Write-Error "Failed to install the Pester module."
}
}
Write-Host "Pester version: $($PesterModule.Version.Major).$($PesterModule.Version.Minor).$($PesterModule.Version.Build)"
$PesterModule | Import-Module
if ($Publish) {
if (!(Test-Path -Path $ResultsPath)) {
New-Item -Path $ResultsPath -ItemType Directory -Force | Out-Null
}
}
$Tests = (Get-ChildItem -Path $($ModulePath) -Recurse | Where-Object { $_.Name -like "*Tests.ps1" }).FullName
$Params = [ordered]@{
Path = $Tests;
Data = @{
ResourceGroupName = $ResourceGroupName;
FunctionAppName = $FunctionAppName;
EventHubNamespaceName = $EventHubNamespaceName;
EventHubNamespaceAuthorizationRuleName = $EventHubNamespaceAuthorizationRuleName;
EventHubName = $EventHubName;
EventHubAuthorizationRuleName = $EventHubAuthorizationRuleName;
EventHubAuthorizationRuleName1 = $EventHubAuthorizationRuleName1;
}
}
$Container = New-PesterContainer @Params
$Configuration = [PesterConfiguration]@{
Run = @{
Container = $Container
}
Output = @{
Verbosity = 'Detailed'
}
TestResult = @{
Enabled = $true
OutputFormat = "NUnitXml"
OutputPath = "$($ResultsPath)\Test-Pester.xml"
}
CodeCoverage = @{
Enabled = $true
Path = $Tests
OutputFormat = "JaCoCo"
OutputPath = "$($ResultsPath)\Pester-Coverage.xml"
}
}
if ($Publish) {
Invoke-Pester -Configuration $Configuration
}
else {
Invoke-Pester -Container $Container -Output Detailed
}
PostDeployment.Tests.ps1
param(
[string]$ResourceGroupName,
[string]$FunctionAppName,
[string]$EventHubNamespaceName,
[string]$EventHubNamespaceAuthorizationRuleName,
[string]$EventHubName,
[string]$EventHubAuthorizationRuleName,
[string]$EventHubAuthorizationRuleName1
)
Describe "Structure Tests" {
BeforeAll {
if ($ResourceGroupName.Length -gt 0) {
$ResourceGroupData = Get-AzResourceGroup -Name $ResourceGroupName
}
if ($EventHubNamespaceName.Length -gt 0) {
$EventHubNamespaceData = Get-AzEventHubNamespace -ResourceGroupName $ResourceGroupName -Name $EventHubNamespaceName
$EventHubNamespaceAuthorizationRuleData = Get-AzEventHubAuthorizationRule -ResourceGroupName $ResourceGroupName -NamespaceName $EventHubNamespaceName -Name $EventHubNamespaceAuthorizationRuleName
}
if ($EventHubName.Length -gt 0) {
$EventHubData = Get-AzEventHub -ResourceGroupName $ResourceGroupName -NamespaceName $EventHubNamespaceName -EventHubName $EventHubName
$EventHubAuthorizationRuleData = Get-AzEventHubAuthorizationRule -ResourceGroupName $ResourceGroupName -NamespaceName $EventHubNamespaceName -EventHubName $EventHubName -Name $EventHubAuthorizationRuleName
$EventHubAuthorizationRuleData1 = Get-AzEventHubAuthorizationRule -ResourceGroupName $ResourceGroupName -NamespaceName $EventHubNamespaceName -EventHubName $EventHubName -Name $EventHubAuthorizationRuleName1
}
if ($FunctionAppName.Length -gt 0) {
$FunctionAppData = Get-AzFunctionApp -Name $FunctionAppName -ResourceGroupName $ResourceGroupName
}
}
# Resource Group
Context -Name "Resource Group" {
It -Name "Passed Resource Group existence check" -Test {
$ResourceGroupData | Should -Not -Be $null
}
}
# Event Hub Namespace
Context -Name "Event Hub Namespace" {
It -Name "Passed Event Hub Namespace existence check" -Test {
$EventHubNamespaceData | Should -Not -Be $null
}
It -Name "Passed Event Hub Namespace tier check" -Test {
$EventHubNamespaceData.Sku.Tier | Should -Be "Standard"
}
It -Name "Passed Event Hub Namespace TU check" -Test {
$EventHubNamespaceData.Sku.Capacity | Should -Be 1
}
It -Name "Passed Event Hub Namespace auto-inflate check" -Test {
$EventHubNamespaceData.IsAutoInflateEnabled | Should -Be $true
}
It -Name "Passed Event Hub Namespace maximum TU check" -Test {
$EventHubNamespaceData.MaximumThroughputUnits | Should -Be 2
}
It -Name "Passed Event Hub Namespace shared access policies check" -Test {
$EventHubNamespaceAuthorizationRuleData.Rights.Count | Should -Be 3
}
}
# Event Hub
Context -Name "Event Hub" {
It -Name "Passed Event Hub existence check" -Test {
$EventHubData | Should -Not -Be $null
}
It -Name "Passed Event Hub 'Listen' shared access policies check" -Test {
$EventHubAuthorizationRuleData.Rights | Should -Be "Listen"
}
It -Name "Passed Event Hub 'Send' shared access policies check" -Test {
$EventHubAuthorizationRuleData1.Rights | Should -Be "Send"
}
}
# Function App
Context -Name "Function App" {
It -Name "Passed Function App existence check" -Test {
$FunctionAppData | Should -Not -Be $null
}
It -Name "Passed Function App AppSettings configuration existence check" -Test {
$FunctionAppData.ApplicationSettings | Should -Not -Be $null
}
It -Name "Passed Function App APPINSIGHTS_INSTRUMENTATIONKEY existence check" -Test {
$FunctionAppData.ApplicationSettings.APPINSIGHTS_INSTRUMENTATIONKEY | Should -Not -Be $null
}
It -Name "Passed Function App FUNCTIONS_WORKER_RUNTIME value check" -Test {
$FunctionAppData.ApplicationSettings.FUNCTIONS_WORKER_RUNTIME | Should -Be "dotnet"
}
}
}
As you can see I am overwriting [PesterConfigruation]::Default with my configuration.
And yes, TestResult block with NUnitXml works as well.
Just add Publish Test Results task at the end of the pipeline. It will pick up the test results and publish them.
Hope this will help someone in the future.