How to Automate Test Plans and Suites With Azure DevOps Pipelines
Managing Azure DevOps Test Plans manually becomes painful fast — especially when every sprint requires:
- A new Test Plan
- New Test Suites for each User Story
- Linking existing Test Cases
- Keeping everything aligned with iteration paths
The good news: you can automate all of it using Azure DevOps REST APIs, PowerShell, and a simple YAML pipeline.
This guide shows you exactly how to:
- Create Test Plans automatically
- Create Test Suites per User Story
- Link Test Cases
- Run everything inside an Azure DevOps Pipeline
Let’s make your sprint setup fully hands‑free.
🧭 1. Why Automate Test Plans and Suites?
Automation solves the biggest pain points in sprint‑based QA:
Benefits
- Zero manual setup — no more clicking through Test Plans UI
- Guaranteed consistency — naming, structure, and traceability stay clean
- Instant sprint readiness — Test Plans are created the moment a sprint starts
- Better DevOps alignment — pipelines become the source of truth
- Scalable — works for 5 stories or 500
🧱 2. Recommended Structure for Automated Test Plans
| Element | Best Practice | Why |
|---|---|---|
| Test Plan | One per sprint | Clean historical record + sprint alignment |
| Test Suite | One per User Story | Perfect traceability |
| Test Cases | Linked to User Story + Suite | Enables reporting + automation |
| Pipeline | One automation pipeline | Runs every sprint or on demand |
⚙️ 3. Azure DevOps REST APIs You Will Use
Azure DevOps exposes the following endpoints for test management:
| Purpose | Endpoint |
|---|---|
| Create Test Plan | POST /_apis/test/plans |
| Create Test Suite | POST /_apis/test/plans/{planId}/suites |
| Add Test Case to Suite | POST /_apis/test/plans/{planId}/suites/{suiteId}/testcases/{testCaseId} |
| Query Work Items (WIQL) | POST /_apis/wit/wiql |
| Get Work Item Details | GET /_apis/wit/workitems/{id} |
All examples below use API version 7.1-preview (current as of 2025).
🧩 4. Full PowerShell Script: Create Test Plans, Suites, and Link Test Cases
This script:
- Creates a Test Plan for the sprint
- Queries all active User Stories in that sprint
- Creates a Static Test Suite for each story
- Finds all linked Test Cases
- Adds them to the suite
It includes improved error handling, logging, and naming conventions.
PowerShell Script (2025 Updated Version)
# ==========================================
# Azure DevOps Test Plan Automation Script
# 2025 Updated Version
# ==========================================
param(
[string]$OrgUrl = "https://dev.azure.com/YOURORG",
[string]$Project = "YOURPROJECT",
[string]$SprintName = "Sprint 18"
)
# Use System.AccessToken inside Azure DevOps Pipeline
$Token = $env:SYSTEM_ACCESSTOKEN
if (-not $Token) {
throw "SYSTEM_ACCESSTOKEN is not available. Enable 'Allow scripts to access OAuth token' in the pipeline."
}
$Headers = @{
Authorization = "Bearer $Token"
"Content-Type" = "application/json"
}
$IterationPath = "$Project\$SprintName"
$AreaPath = $Project
Write-Host "🔧 Starting automation for $SprintName..."
# ---------------------------------------------------------
# 1. Create Test Plan
# ---------------------------------------------------------
$PlanBody = @{
name = "$SprintName - Test Plan"
area = @{ path = $AreaPath }
iteration = $IterationPath
} | ConvertTo-Json -Depth 10
$PlanUri = "$OrgUrl/$Project/_apis/test/plans?api-version=7.1-preview.1"
$Plan = Invoke-RestMethod -Uri $PlanUri -Method Post -Headers $Headers -Body $PlanBody
$PlanId = $Plan.id
Write-Host "📘 Created Test Plan: $PlanId"
# ---------------------------------------------------------
# 2. Query User Stories in Sprint
# ---------------------------------------------------------
$Wiql = @"
SELECT [System.Id], [System.Title]
FROM WorkItems
WHERE [System.WorkItemType] = 'User Story'
AND [System.State] <> 'Closed'
AND [System.IterationPath] = '$IterationPath'
"@
$QueryBody = @{ query = $Wiql } | ConvertTo-Json
$QueryUri = "$OrgUrl/$Project/_apis/wit/wiql?api-version=7.1-preview.2"
$UserStories = Invoke-RestMethod -Uri $QueryUri -Method Post -Headers $Headers -Body $QueryBody
if ($UserStories.workItems.Count -eq 0) {
Write-Host "⚠️ No active User Stories found for $SprintName."
exit 0
}
# ---------------------------------------------------------
# 3. Create Test Suites + Link Test Cases
# ---------------------------------------------------------
foreach ($Story in $UserStories.workItems) {
$StoryId = $Story.id
$StoryDetails = Invoke-RestMethod -Uri "$OrgUrl/$Project/_apis/wit/workitems/$StoryId?api-version=7.1-preview.3" -Headers $Headers
$StoryTitle = $StoryDetails.fields.'System.Title'
Write-Host "🧩 Processing User Story $StoryId - $StoryTitle"
# Create Static Suite
$SuiteBody = @{
suiteType = "StaticTestSuite"
name = "US$StoryId - $StoryTitle"
} | ConvertTo-Json -Depth 10
$SuiteUri = "$OrgUrl/$Project/_apis/test/plans/$PlanId/suites?api-version=7.1-preview.3"
$Suite = Invoke-RestMethod -Uri $SuiteUri -Method Post -Headers $Headers -Body $SuiteBody
$SuiteId = $Suite.id
Write-Host "📁 Created Suite $SuiteId for User Story $StoryId"
# Get linked Test Cases
$Relations = $StoryDetails.relations `
| Where-Object { $_.rel -eq "System.LinkTypes.Hierarchy-Forward" -and $_.url -match "/workItems/" }
$TestCaseIds = @()
foreach ($Rel in $Relations) {
if ($Rel.url -match "/workItems/(\d+)") {
$TestCaseIds += $Matches[1]
}
}
if ($TestCaseIds.Count -eq 0) {
Write-Host "⚠️ No test cases linked to User Story $StoryId"
continue
}
# Add Test Cases to Suite
foreach ($TcId in $TestCaseIds) {
$AddUri = "$OrgUrl/$Project/_apis/test/plans/$PlanId/suites/$SuiteId/testcases/$TcId?api-version=7.1-preview.3"
Invoke-RestMethod -Uri $AddUri -Method Post -Headers $Headers
Write-Host "🔗 Linked Test Case $TcId → Suite $SuiteId"
}
}
Write-Host "🎉 Automation complete for $SprintName!"
🚀 5. YAML Pipeline to Run the Automation
This pipeline:
- Runs the PowerShell script
- Passes sprint name dynamically
- Uses
System.AccessToken - Can be scheduled or triggered manually
azure-pipelines.yml
trigger: none
parameters:
- name: sprintName
type: string
default: "Sprint 18"
pool:
vmImage: 'windows-latest'
steps:
- checkout: self
- task: PowerShell@2
displayName: "Automate Test Plan + Suites"
inputs:
targetType: inline
script: |
Write-Host "Running automation for: $"
./automation/Create-TestPlan.ps1 `
-OrgUrl "https://dev.azure.com/YOURORG" `
-Project "YOURPROJECT" `
-SprintName "$"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
🧠 6. Best Practices for Automated Test Plan Management
| Area | Best Practice |
|---|---|
| Naming | Use US1234 - Title for suites |
| Traceability | Always link Test Cases to User Stories |
| Regression | Keep a separate long‑lived Regression Plan |
| Automation | Run this pipeline at sprint creation |
| Governance | Lock Test Plans after sprint ends |
🏁 Conclusion
Automating your Azure DevOps Test Plans removes repetitive manual work and ensures your sprint structure is always:
- Clean
- Consistent
- Traceable
- Audit‑ready
- Automation‑friendly
With PowerShell + Azure DevOps REST APIs + YAML pipelines, you can generate an entire sprint’s test structure in seconds — and focus your time on actual testing, not setup.

🗨️ Reader Comments