Saturday, April 20, 2013

How To Create a Test Plans and Cases Migration Tool For TFS : Part 3 - Duplicating Shared steps and action steps.

In my last post - How To Create a Test Plans and Cases Migration Tool For TFS : Part 2,  I showed how to migrate Test plans, suits, cases from one project to another, programmatically using Test Management API. In this post I'll show how to copy test steps of each test cases including shared steps. 

First of all we iterate all test steps of a test case. Then we try to see whether there is a shared reference for that test step. if it has an reference then it is a shared step, otherwise it's just a normal test step.

Code for duplication of test steps:
                   
                foreach (ITestAction action in testcase.TestCase.Actions)
                {

                    ISharedStep shared_step = null;
                    ISharedStepReference shared_ref = action as ISharedStepReference;
                    if (shared_ref != null)
                    {
                        shared_step = shared_ref.FindSharedStep();
                        foreach (ITestAction shr_action in shared_step.Actions)
                        {
                            ITestStep test_step = shr_action as ITestStep; ;
                            ITestStep destinationStep = tc.CreateTestStep();
                            destinationStep.Title = test_step.Title;
                            destinationStep.ExpectedResult = test_step.ExpectedResult;
                            tc.Actions.Add(destinationStep);
                        }

                    }
                    else
                    {
                        var test_step = action as ITestStep;
                        ITestStep destinationStep = tc.CreateTestStep();
                        destinationStep.Title = test_step.Title;
                        tc.Actions.Add(destinationStep);
                    }
                }



Full Code:

 public partial class MainWindow : Window
    {
        string sourceserverurl = "http://gandalf:8080/tfs/defaultcollection";
        string sourceproject = "Sample Project";
        string destinationtfs = "http://aragon:8080/tfs/defaultcollection";
        string destinationproject = "PMTest";
        ITestManagementTeamProject sourceproj;
        ITestManagementTeamProject destinationproj;    

        public MainWindow()
        {
            InitializeComponent();
            sourceproj = GetProject(sourceserverurl, sourceproject);
            destinationproj = GetProject(destinationtfs, destinationproject);
        }

        private ITestManagementTeamProject GetProject(string serverUrl, string project)
        {
            TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverUrl));
            ITestManagementService tms = tfs.GetService<ITestManagementService>();

            return tms.GetTeamProject(project);
        }

        void CopyTestPlans()
        {

            foreach (ITestPlan destinationplan in destinationproj.TestPlans.Query("Select * From TestPlan"))
            {

                System.Diagnostics.Debug.WriteLine("Deleting Plan - {0} : {1}", destinationplan.Id, destinationplan.Name);

                destinationplan.Delete(DeleteAction.ForceDeletion); ;

            }

            foreach (ITestPlan sourceplan in sourceproj.TestPlans.Query("Select * From TestPlan"))
            {
                System.Diagnostics.Debug.WriteLine("Plan - {0} : {1}", sourceplan.Id, sourceplan.Name);

                ITestPlan destinationplan = destinationproj.TestPlans.Create();
                destinationplan.Name = sourceplan.Name;
                destinationplan.Description = sourceplan.Description;
                destinationplan.StartDate = sourceplan.StartDate;
                destinationplan.EndDate = sourceplan.EndDate;
                destinationplan.State = sourceplan.State;

                if (sourceplan.RootSuite != null && sourceplan.RootSuite.Entries.Count > 0)
                {
                    CopyTestSuites(sourceplan, destinationplan);
                }

                destinationplan.Save();
            }
        }

        void CopyTestSuites(ITestPlan sourceplan, ITestPlan destinationplan)
        {
            ITestSuiteEntryCollection suites = sourceplan.RootSuite.Entries;

            foreach (ITestSuiteEntry suite_entry in suites)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite newSuite = destinationproj.TestSuites.CreateStatic();
                    newSuite.Title = suite.Title;
                    destinationplan.RootSuite.Entries.Add(newSuite); 
                    destinationplan.Save();

                    CopyTestCases(suite, newSuite);
                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, newSuite);
                }
            }
        }

        void CopySubTestSuites(IStaticTestSuite parentsourceSuite, IStaticTestSuite parentdestinationSuite)
        {
            ITestSuiteEntryCollection suitcollection = parentsourceSuite.Entries;
            foreach (ITestSuiteEntry suite_entry in suitcollection)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite subSuite = destinationproj.TestSuites.CreateStatic();
                    subSuite.Title = suite.Title;
                    parentdestinationSuite.Entries.Add(subSuite);

                    CopyTestCases(suite, subSuite);

                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, subSuite);

                }     
            }          
        }

        void CopyTestCases(IStaticTestSuite sourcesuite, IStaticTestSuite destinationsuite)
        {
            ITestCaseCollection dd=sourcesuite.AllTestCases;
            ITestSuiteEntryCollection suiteentrys = sourcesuite.TestCases;

            foreach (ITestSuiteEntry testcase in suiteentrys)
            {
                ITestCase tc = destinationproj.TestCases.Create();
                tc.Title = testcase.Title;
                tc.Priority = testcase.TestCase.Priority;
               
                 foreach (ITestAction action in testcase.TestCase.Actions)
                {
                    ISharedStep shared_step = null;
                    ISharedStepReference shared_ref = action as ISharedStepReference;
                    if (shared_ref != null)
                    {
                        shared_step = shared_ref.FindSharedStep();
                        foreach (ITestAction shr_action in shared_step.Actions)
                        {
                            ITestStep test_step = shr_action as ITestStep; ;
                            ITestStep destinationStep = tc.CreateTestStep();
                            destinationStep.Title = test_step.Title;
                            destinationStep.ExpectedResult = test_step.ExpectedResult;
                            tc.Actions.Add(destinationStep);
                        }

                    }
                    else
                    {
                        var test_step = action as ITestStep;
                        ITestStep destinationStep = tc.CreateTestStep();
                        destinationStep.Title = test_step.Title;
                        tc.Actions.Add(destinationStep);
                    }
                }
                tc.Save();
                destinationsuite.Entries.Add(tc);
            }
        }

        private void btn_connect_Click(object sender, RoutedEventArgs e)
        {
            CopyTestPlans();
        }
        
    }


Thursday, April 18, 2013

How To Create a Test Plans and Cases Migration Tool For TFS : Part 2 - Copy Test Plans, Suits and Test cases.

In my last post -How To Create a Test Plans and Cases Migration Tool For TFS : Part 1,  I showed how to create and manage Test plans, suits, cases programmatically using Test Management API. The knowledge of basics is necessary in order to understand the functionality of the Test Plans and Cases migration tool we intended to build. In this post let's focus on about how to get all the test suits and test cases in a test plan. This is bit tricky as test suits can be nested within test suits. 
Once again you’ll need to add references to the following assemblies to your project.
  • Microsoft.TeamFoundation.Client.dll 
  • Microsoft.TeamFoundation.TestManagement.Client.dll 
  • Microsoft.TeamFoundation.TestManagement.Common.dll 
  • Microsoft.TeamFoundation.WorkItemTracking.Client.dll 
These assemblies are located at:C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0


Step 1: Connect to source and target projects 

        string sourceserverurl = "http://gandalf:8080/tfs/defaultcollection";
        string sourceproject = "Sample Project";
        string destinationtfs = "http://aragon:8080/tfs/defaultcollection";
        string destinationproject = "PMTest";

        ITestManagementTeamProject sourceproj;
        ITestManagementTeamProject destinationproj;
        sourceproj = GetProject(sourceserverurl, sourceproject);
        destinationproj = GetProject(destinationtfs, destinationproject);


ITestManagementTeamProject GetProject(string serverUrl, string project)
{
  TfsTeamProjectCollection tfs = new  TfsTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverUrl));
  ITestManagementService tms = tfs.GetService<ITestManagementService>();

   return tms.GetTeamProject(project);
}


Step 2: Copy Test Plans from source to target project

foreach (ITestPlan sourceplan in sourceproj.TestPlans.Query("Select * From TestPlan"))
            {
                ITestPlan destinationplan = destinationproj.TestPlans.Create();
                destinationplan.Name = sourceplan.Name;
                destinationplan.Description = sourceplan.Description;
                destinationplan.StartDate = sourceplan.StartDate;
                destinationplan.EndDate = sourceplan.EndDate;
                destinationplan.State = sourceplan.State;
                destinationplan.Save();
            }

Step 3: Check whether any root test suits exist for a test plan

 if (sourceplan.RootSuite != null && sourceplan.RootSuite.Entries.Count > 0)
{
                    CopyTestSuites(sourceplan, destinationplan);
}

Step 4: Copy Root Test  suits from source  to target plan

void CopyTestSuites(ITestPlan sourceplan, ITestPlan destinationplan)
        {
            ITestSuiteEntryCollection suites = sourceplan.RootSuite.Entries;

            foreach (ITestSuiteEntry suite_entry in suites)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite newSuite = destinationproj.TestSuites.CreateStatic();
                    newSuite.Title = suite.Title;
                    destinationplan.RootSuite.Entries.Add(newSuite); 
                    destinationplan.Save();

                   //Check whether root suite contains nested suits
                    CopyTestCases(suite, newSuite);
                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, newSuite);
                }
            }

        }

Step 5: Recursively copy nested Test suits 

 void CopySubTestSuites(IStaticTestSuite parentsourceSuite, IStaticTestSuite parentdestinationSuite)
        {
            ITestSuiteEntryCollection suitcollection = parentsourceSuite.Entries;
            foreach (ITestSuiteEntry suite_entry in suitcollection)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite subSuite = destinationproj.TestSuites.CreateStatic();
                    subSuite.Title = suite.Title;
                    parentdestinationSuite.Entries.Add(subSuite);
                    // call to copy test cases that contains in the leaf test suite.
                    CopyTestCases(suite, subSuite);

                    // check whether if test suit contains nested test suits
                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, subSuite);
                }     
            }        
        }

Step 6: Copy Test cases from source to target plan

 void CopyTestCases(IStaticTestSuite sourcesuite, IStaticTestSuite destinationsuite)
        {
            ITestCaseCollection dd=sourcesuite.AllTestCases;
            ITestSuiteEntryCollection suiteentrys = sourcesuite.TestCases;

            foreach (ITestSuiteEntry testcase in suiteentrys)
            {
                ITestCase tc = destinationproj.TestCases.Create();
                tc.Title = testcase.Title;
                tc.Priority = testcase.TestCase.Priority;
                tc.Save();
                destinationsuite.Entries.Add(tc);
            }
        }

Full Code:

 public partial class MainWindow : Window
    {
        string sourceserverurl = "http://gandalf:8080/tfs/defaultcollection";
        string sourceproject = "Sample Project";
        string destinationtfs = "http://zeus:8080/tfs/defaultcollection";
        string destinationproject = "PMTest";
        ITestManagementTeamProject sourceproj;
        ITestManagementTeamProject destinationproj;    

        public MainWindow()
        {
            InitializeComponent();
            sourceproj = GetProject(sourceserverurl, sourceproject);
            destinationproj = GetProject(destinationtfs, destinationproject);
        }

        private ITestManagementTeamProject GetProject(string serverUrl, string project)
        {
            TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverUrl));
            ITestManagementService tms = tfs.GetService<ITestManagementService>();

            return tms.GetTeamProject(project);
        }

        void CopyTestPlans()
        {

            foreach (ITestPlan destinationplan in destinationproj.TestPlans.Query("Select * From TestPlan"))
            {

                System.Diagnostics.Debug.WriteLine("Deleting Plan - {0} : {1}", destinationplan.Id, destinationplan.Name);

                destinationplan.Delete(DeleteAction.ForceDeletion); ;

            }

            foreach (ITestPlan sourceplan in sourceproj.TestPlans.Query("Select * From TestPlan"))
            {
                System.Diagnostics.Debug.WriteLine("Plan - {0} : {1}", sourceplan.Id, sourceplan.Name);

                ITestPlan destinationplan = destinationproj.TestPlans.Create();
                destinationplan.Name = sourceplan.Name;
                destinationplan.Description = sourceplan.Description;
                destinationplan.StartDate = sourceplan.StartDate;
                destinationplan.EndDate = sourceplan.EndDate;
                destinationplan.State = sourceplan.State;

                if (sourceplan.RootSuite != null && sourceplan.RootSuite.Entries.Count > 0)
                {
                    CopyTestSuites(sourceplan, destinationplan);
                }

                destinationplan.Save();
            }
        }

        void CopyTestSuites(ITestPlan sourceplan, ITestPlan destinationplan)
        {
            ITestSuiteEntryCollection suites = sourceplan.RootSuite.Entries;

            foreach (ITestSuiteEntry suite_entry in suites)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite newSuite = destinationproj.TestSuites.CreateStatic();
                    newSuite.Title = suite.Title;
                    destinationplan.RootSuite.Entries.Add(newSuite); 
                    destinationplan.Save();

                    CopyTestCases(suite, newSuite);
                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, newSuite);
                }
            }
        }

        void CopySubTestSuites(IStaticTestSuite parentsourceSuite, IStaticTestSuite parentdestinationSuite)
        {
            ITestSuiteEntryCollection suitcollection = parentsourceSuite.Entries;
            foreach (ITestSuiteEntry suite_entry in suitcollection)
            {
                IStaticTestSuite suite = suite_entry.TestSuite as IStaticTestSuite;
                if (suite != null)
                {
                    IStaticTestSuite subSuite = destinationproj.TestSuites.CreateStatic();
                    subSuite.Title = suite.Title;
                    parentdestinationSuite.Entries.Add(subSuite);

                    CopyTestCases(suite, subSuite);

                    if (suite.Entries.Count > 0)
                        CopySubTestSuites(suite, subSuite);

                }     
            }          
        }

        void CopyTestCases(IStaticTestSuite sourcesuite, IStaticTestSuite destinationsuite)
        {
            ITestCaseCollection dd=sourcesuite.AllTestCases;
            ITestSuiteEntryCollection suiteentrys = sourcesuite.TestCases;

            foreach (ITestSuiteEntry testcase in suiteentrys)
            {
                ITestCase tc = destinationproj.TestCases.Create();
                tc.Title = testcase.Title;
                tc.Priority = testcase.TestCase.Priority;
                tc.Save();
                destinationsuite.Entries.Add(tc);
            }
        }

        private void btn_connect_Click(object sender, RoutedEventArgs e)
        {
            CopyTestPlans();
        }
        
    }


Next time let's discuss how to add action steps and  duplicate shared steps of test cases in target server.

Sunday, April 14, 2013

How To Create a Test Plans and Cases Migration Tool For TFS : Part 1

Recently We had to move some team projects from TFS 2010 Server to a newly created TFS 2012 Server. This involves moving all source files,work items, attachments, links and team queries. Though moving source files is an easy task, moving work items is not an easy feat. This is due to many reasons. Such as TFS 2010 use the Scrum 1.0 template and TFS 2012  use Scrum 2.0 template(Update 2 use 2.2 template). Migration is done through the APIs of TFS by using external tools, and is a lossy data transfer. There is a migration tool named TFS Integration Tools developed by TFS product group  and the Visual Studio ALM Rangers. This product is not 100% generic and it has certain limitations; such as not supporting test case migration, permission, etc. Therefore we decided to built a much more generic tool that match our need.



As a part of the process We had to transfer all the Test Plans, Test suits and associated test cases. These Test plans and suits are built and maintained using Microsoft Test Manager. I build a tool which enables migrate test plans from one project to another.(projects may be reside in one project collection or or may be reside on two servers) For this task I had to use Test Management API  in order to add Test Plan programmatically. With the API anyone could create their own solution or a custom tool that fits their individual needs for migrating data between systems.  


Before creating tool,first of all let's get an idea about how to create and edit test plans, suits and test cases.


You’ll need to add references to the following assemblies to your project.

  • Microsoft.TeamFoundation.Client.dll 
  • Microsoft.TeamFoundation.TestManagement.Client.dll 
  • Microsoft.TeamFoundation.TestManagement.Common.dll 
  • Microsoft.TeamFoundation.WorkItemTracking.Client.dll 
These assemblies are located at:C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0

Step 1: Connect to Team Foundation Server

string sourceserverurl = "http://localhost:8080/tfs/defaultcollection";
string sourceproject = "General";

ITestManagementTeamProject project = GetProject(sourceserverurl, sourceproject);


ITestManagementTeamProject GetProject(string serverUrl, string project)
{
  TfsTeamProjectCollection tfs = new  TfsTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverUrl));
  ITestManagementService tms = tfs.GetService<ITestManagementService>();

   return tms.GetTeamProject(project);
}


Step 2: Create a Test Plan Programmatically
            
            ITestPlan plan = project.TestPlans.Create();
            plan.Name = " First Test Plan";
            plan.StartDate = DateTime.Now;
            plan.EndDate = DateTime.Now.AddMonths(2);
            // other attributes: plan.AreaPath, plan.Description,plan.State
            plan.Save();

Step 3: Create a Test Suite Programmatically
          
            IStaticTestSuite newSuite = project.TestSuites.CreateStatic();
            newSuite.Title = "Test Suite";        
            plan.RootSuite.Entries.Add(newSuite);
            plan.Save();

Step 4: Create a Test Case Programmatically
           
            ITestCase tc = project.TestCases.Create();
            tc.Title = "Test case 1";
            tc.Save();
            newSuite.Entries.Add(tc);
            plan.Save();

Step 5: List all Test Plans
           
            foreach (ITestPlan p in project.TestPlans.Query("Select * From TestPlan"))
            {
                Console.WriteLine("Plan - {0} : {1}", p.Id, p.Name);
            }

Additional: Delete a Test Plan

            plan.Delete(DeleteAction.ForceDeletion);

Step 6: List all test suits and test cases.

foreach (ITestSuiteBase suite in plan.RootSuite.SubSuites)
{
     Console.WriteLine("\tTest Suite: {0}", suite.Title);

     IStaticTestSuite staticSuite = suite as IStaticTestSuite;

     // Let's Query the Test Points.
    foreach(ITestPoint point in plan.QueryTestPoints(
                    string.Format("SELECT * FROM TestPoint WHERE SuiteId = {0}",
                    suite.Id)))
    {
                    Console.WriteLine("\t\tTest Point for Testcase \"{0}\" against config \"{1}\"",
                        point.TestCaseWorkItem.Title, point.ConfigurationName);                        
     }
}

Full Code:

namespace TFSMigrationApp
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            string sourceserverurl = "http://localhost:8080/tfs/defaultcollection";
            string sourceproject = "General";

            ITestManagementTeamProject project = GetProject(sourceserverurl, sourceproject);

            // List all Test Plans before adding new plan
            foreach (ITestPlan p in project.TestPlans.Query("Select * From TestPlan"))
            {
                Console.WriteLine("Plan - {0} : {1}", p.Id, p.Name);
            }

            // creating a new Test Plan from scratch
            ITestPlan plan = project.TestPlans.Create();
            plan.Name = "My New Test Plan";
            plan.StartDate = DateTime.Now;
            plan.EndDate = DateTime.Now.AddMonths(2);
            plan.Save();

            Console.WriteLine("Created new Plan \"{0}\" with Id: {1}",
                plan.Name, plan.Id);

            //addding a new Test Suite to our plan
            IStaticTestSuite newSuite = project.TestSuites.CreateStatic();
            newSuite.Title = "Test Suite";         
            plan.RootSuite.Entries.Add(newSuite);
            plan.Save();

            // creating a Testcase to add to our Test Suite
            ITestCase tc = project.TestCases.Create();
            tc.Title = "Test case 1";
            tc.Save();
            newSuite.Entries.Add(tc);
            plan.Save();


            // List all Test Plans
            foreach (ITestPlan p in project.TestPlans.Query("Select * From TestPlan"))
            {
                Console.WriteLine("Plan - {0} : {1}", p.Id, p.Name);
            }

            //List all test suits and test cases.
            foreach (ITestSuiteBase suite in plan.RootSuite.SubSuites)
            {
                Console.WriteLine("\tTest Suite: {0}", suite.Title);

                IStaticTestSuite staticSuite = suite as IStaticTestSuite;

                // Let's Query the Test Points.
                foreach (ITestPoint point in plan.QueryTestPoints(
                    string.Format("SELECT * FROM TestPoint WHERE SuiteId = {0}",
                    suite.Id)))
                {
                    Console.WriteLine("\t\tTest Point for Testcase \"{0}\" against config \"{1}\"",
                        point.TestCaseWorkItem.Title, point.ConfigurationName);                        
                }
            }
        }

        static ITestManagementTeamProject GetProject(string serverUrl,
           string project)
        {
            TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverUrl));
            ITestManagementService tms = tfs.GetService<ITestManagementService>();

            return tms.GetTeamProject(project);
        }

       
    }
}