If you work with ARM templates and Azure DevOps, you know that there is already tight integration between the two. Giving you a pretty simple method of deploying a template via a YAML Pipeline just by plugging in a few details. However, as your pipelines progress in complexity, or perhaps importance, the need for additional services like triggers, filters, and testing becomes apparent.
Having familiarity with ARM templates most likely means you are aware of the test toolkit, if not, here is a link to the docs page explaining what it is, how it works etc.
This post presumes you have knowledge of ARM Template deployment, Azure DevOps Pipelines, and a Project and Repo setup. However, as with any code on a blog, please be careful, use a sandbox first, I cannot help with your production environment. π If you’re new to this, there is a good tutorial here by Microsoft.
So, with your ARM template ready to go, you can deploy in a single task from a Pipeline. However, if this fails it can cause problems. Generally, more complex Pipelines will include the use of Stages and Jobs. In this example, we’re going to use a multi-stage Pipeline that will validate, test, report test results and if all successful, deploy our ARM template to Azure.
All of the below is included in a public Github repo here – https://github.com/wedoazure/blogAZNet
First, let’s take a look at the pipeline at a high level

This breaks out as follows:
- Two stages – Test and Deploy
- Two jobs in Test
- A single job in Deploy
Within each job we may have multiple tasks and we will see that a bit later.
First up, lets look at the first job in the Test Stage, “testARM”. This job includes multiple tasks, with some built-in tasks and some imported. The first thing to address here is the task that is imported.
This takes the ARM Template Test Toolkit and allows you to import the functionality to Azure DevOps. My personal experience is with Sam Cogan’s build linked here, although there may be others. Once imported you can then use via the task assistant:

An added bonus, the extension supports both ARM and Bicep file testing. I have both included in the repo but this focusses on ARM. You can check the repo for Bicep details, or get in touch!
So with our task imported, let’s look at our code:
First up, we’re going to validate the template using the built ARM deploy task, switching deployment mode to validation.
stages:
- stage: Test
jobs:
- job: 'testARM'
pool:
vmimage: windows-latest
steps:
- task: AzureResourceManagerTemplateDeployment@3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'Your Connection'
subscriptionId: 'XXXXXXXXXXXXXXXXXXXXXXXXX'
action: 'Create Or Update Resource Group'
resourceGroupName: 'rg_staging'
location: 'North Europe'
templateLocation: 'Linked artifact'
csmFile: 'virtualNetworks/vnet-ne.json'
csmParametersFile: 'virtualNetworks/vnet-ne.parameters.json'
deploymentMode: 'Validation'
deploymentName: 'ARM-Validation'
This is a lightning quick test to ensure everything is OK with your template. Next, we’re going to use our imported task to run multiple checks against the template using the approved toolkit. This needs to run on a Windows pool by the way!
- task: RunARMTTKTests@1
inputs:
templatelocation: '$(System.DefaultWorkingDirectory)\virtualNetworks'
resultLocation: '$(System.DefaultWorkingDirectory)\testResults'
allTemplatesMain: true
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '$(System.DefaultWorkingDirectory)\testResults\*-armttk.xml'
condition: always()
Note we have two tasks here, the first runs the tests and outputs the results. The second is a built-in task to publish your results to Azure DevOps, giving users a graphical representation in the portal as well as test history. The condition ensures the publish task will complete regardless of the previous task failing.

Next, we move onto the second job of our Test Stage.
- job: 'validateARM'
pool:
vmimage: windows-latest
steps:
- task: AzurePowerShell@5
inputs:
azureSubscription: 'Your SC'
ScriptType: 'InlineScript'
Inline: |
$Parameters = @{
ResourcegroupName = "rg_iac"
Templatefile = ".\virtualNetworks\vnet-ne.json"
TemplateParameterfile = ".\virtualNetworks\vnet-ne.parameters.json"
Mode = 'Incremental'
}
$Result = Get-AzResourceGroupDeploymentWhatIfResult @Parameters
$Result
azurePowerShellVersion: 'LatestVersion'
This runs an Azure Powershell task, submitting your template using the built in “What If Result” cmdlet. I really like this one, it outputs a full detail of changes etc. If you haven’t tried it with an ARM template you really should. Below is a sample output from my pipeline:

Now, if all the above passes, the Pipeline will move onto the next Stage, Deploy. I’ve added a DependsOn to ensure this is the case. If the Test Stage doesn’t complete, this Stage will be skipped.
- stage: Deploy
dependsOn: Test
jobs:
- job: "deployARM"
pool:
vmimage: windows-latest
steps:
- task: AzureResourceManagerTemplateDeployment@3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'Your SC'
subscriptionId: 'XXXXXXXXXXXXXXXXXXXXXX'
action: 'Create Or Update Resource Group'
resourceGroupName: 'rg_iac'
location: 'North Europe'
templateLocation: 'Linked artifact'
csmFile: 'virtualNetworks/vnet-ne.json'
csmParametersFile: 'virtualNetworks/vnet-ne.parameters.json'
deploymentMode: 'Incremental'
deploymentName: 'vnet-deploy-ado'
This again uses the built in ARM deployment task with a deployment mode of Incremental. The logic here is that if all of my Test Stage passes, I have a high percentage chance of my template deploying fully without issue.
The above has worked well for me in testing and with some variations in production environments. Feel free to experiment as needed here. One thing I have learned is there is an ever evolving set of methods and best practices. Alignment, in my opinion, should be to what works for you.
As always, if there are any questions or suggestions, get in touch!
4 thoughts on “How to – ARM Template Test Toolkit on Azure DevOps”