Rollback tests with TFS/VSTS


In this post, Premier ADM Mike Lapierre covers techniques to rollback bulk editing changes with TFS test cases.


I was assisting a customer recently who was working on many TFS test cases, using Excel for bulk editing.  The Excel integration is great for editing regular fields but it can’t handle HTML fields like the description or the test steps.  When such a field is modified, the following message is displayed.

rollback1

We all take time to read such messages, right?  Okay, maybe not all the time.  Once you publish the test cases and the damage is done, how can you get back to the previous state?  The short answer is there’s no rollback mechanism built in, so you must get the previous values from the history, put them back in, and save the test case.  Furthermore, test steps are all stored in a single field so you must split them back for the UI.  This might be a viable solution for a few test cases, but if we’re talking about hundreds of test cases, it’s not.

So, what’s the long answer?  We can use the TFS APIs to get the values from a previous revision and put them back in the test case before saving.  The solution is the same, but it’s automated and scales well to any number of test cases.

I chose to use PowerShell to build the script, but this can also be done from any .NET application in the language of your choosing.  For starters, we need to load the required TFS APIs in the PowerShell session.  I am using Visual Studio / Team Explorer 2015, so the APIs can be found in the folder below.

 

$AssemblyFolder = “${Env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer”

[System.Reflection.Assembly]::LoadFrom(“$AssemblyFolder\Microsoft.TeamFoundation.Client.dll”)

[System.Reflection.Assembly]::LoadFrom(“$AssemblyFolder\Microsoft.TeamFoundation.TestManagement.Client.dll”)

 

The next step is to connect to the Team Project Collection and grab the Test Management service and the desired Team Project.

 

$TargetProject = “Team Project”

$TargetUrl = “http://host:port/tfs/collection

$TargetTFS = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(New-Object System.Uri($TargetUrl))

$TargetTestMgmt = $TargetTFS.GetService([Microsoft.TeamFoundation.TestManagement.Client.ITestManagementService])

$TargetTeamProject = $TargetTestMgmt.GetTeamProject($TargetProject)

We now need to locate the test cases we want to rollback.  Test cases are basically work items with extra features on top.  Their history / revision is handled by work items.  To locate the work items, you can get fancy with the WIQL language, but the easiest way is to use IDs.

 

$TargetIds = “(1,2,3)”

$WorkItems = $TargetTeamProject.WitProject.Store.Query(“SELECT * FROM WorkItems WHERE [System.Id] IN $TargetIds”)

 

Now we have the affected work items, we must spot which revision we want to restore for each work item.  Again, you can use different methods for this, but let’s use the “Back to Future” technique and set destination time to where we want to fix.

 

$TargetDate = Get-Date -Year 1985 -Month 10 -Day 26 -Hour 09 -Minute 00 -Second 00

$GoodRevision = $WorkItem.Revisions | ? { $_.Fields[“System.ChangedDate”].Value -lt $TargetDate } | select -Last 1

 

It’s time to compare the last good revision with current revision. There’s three possibilities here:

  1. There’s no revision before the specified date: nothing to do, the test case did not exist.
  2. The current revision and the last good revision are the same: nothing to do, the test case has not been updated after the specified date.
  3. The current revision is different from the last good revision: we must restore the test case with the last good revision.

Since we have to this for each work item, let’s express it as a for loop (with a bit of logging).

 

$TargetDate = Get-Date -Year 1985 -Month 10 -Day 26 -Hour 09 -Minute 00 -Second 00

foreach($WorkItem in $WorkItems)

{

   $GoodRevision = $WorkItem.Revisions | ? { $_.Fields[“System.ChangedDate”].Value -lt $TargetDate } | select -Last 1

   if ($GoodRevision)

   {

      if ($WorkItem.Rev -eq $GoodRevision.Fields[“System.Rev”].Value)

      {

         Write-Verbose “Test Case $($WorkItem.Id) has no revision after $TargetDate”

      }

      else

      {

         Write-Verbose “Test Case $($WorkItem.Id) will be updated with revision $($GoodRevision.Fields[“System.Rev”].Value) ($($GoodRevision.Fields[“System.ChangedDate”].Value))”

         # Restore the test case

      }

   }

   else

   {

      Write-Verbose “Test Case $($WorkItem.Id) has no revision before $TargetDate”

   }

}

The final step is to restore the test case with last good revision.  You can choose the fields you want to restore.  In this case, let’s restore the description, steps, parameters, and their values.

 

$TestCase = $TargetTeamProject.TestCases.Find($WorkItem.Id)

$TestCase.Description = $GoodRevision.Fields[“System.Description”].Value

($TestCase.CustomFields | ? { $_.ReferenceName -eq “Microsoft.VSTS.TCM.Steps” }).Value = $GoodRevision.Fields[“Microsoft.VSTS.TCM.Steps”].Value

($TestCase.CustomFields | ? { $_.ReferenceName -eq “Microsoft.VSTS.TCM.Parameters” }).Value = $GoodRevision.Fields[“Microsoft.VSTS.TCM.Parameters”].Value

($TestCase.CustomFields | ? { $_.ReferenceName -eq “Microsoft.VSTS.TCM.LocalDataSource” }).Value = $GoodRevision.Fields[“Microsoft.VSTS.TCM.LocalDataSource”].Value

$TestCase.Save()

 

That’s it!  We have successfully traveled through time to make sure we read the dialog box!  You can find the full script on GitHub.

Note this technique can be used for regular work items too by using the Work Item API only instead of both the Work Item and Test Management APIs.

If you want to run this against VSTS, you’ll have to get a Personal Access Token, and add the following property assignment:

 

$TargetTFS.ClientCredentials = New-Object Microsoft.TeamFoundation.Client.TfsClientCredentials(New-Object Microsoft.TeamFoundation.Client.BasicAuthCredential(New-Object System.Net.NetworkCredential(“”, “pat”)))

 

I hope this post helps you!


Premier Support for Developers provides strategic technology guidance, critical support coverage, and a range of essential services to help teams optimize development lifecycles and improve software quality.  Contact your Application Development Manager (ADM) or email us to learn more about what we can do for you.

Comments (0)

Skip to main content