本篇承接上篇Windows phone 应用开发[9]-单元测试,当在Unit TEst 确定了测试用例的方案.在单个模块单元测试通过开始走模块之间集成时.其实很多测试工作就可以开发人员手中开始向测试人员转移.类似针对单个模块,测试团队可以根据已经确定测试用例批量执行.得到实际结果与期望结果进行比较.而这个过程测试执行者无需了解代码如何执行.也就是俗称黑盒测试.

    而对于单个模块的回归测试而言.为了提高效率引入自动化测试的概念.可惜的是目前并没有任何可用于Windows phone Application应用程序的自动化测试工具.曾在Silverlight中使用过自动化测试工具-Ranorex,花费点时间尝试通过Ranorex在WP 上执行自动化测试.发现存在很多应用程序与测试工具之间很多不可控的问题.

    那么对于单个模块回归测试而言.需要哪些过程可以自动化?分析如下:

自动化流程:

[1]:模拟器控制-启动或关闭Windows phone 模拟器.

[2]: 自动在模拟器上安装并执行测试用例应用程序.

[3]: 收集测试结果

[4]: 卸载测试用应用程序前恢复模拟器

 

 

    now,如果我们把这个过程自动化处理.问题就出现了如何在不使用Application Development Tool情况把XAP安装包安装到模拟器或真机上? 同样针对模拟器控制.如何能够在代码自动控制并运行XAP安装包?

    针对这个问题.Windows phone 类库中提供一个Microsoft.SmartDevice.Connectivity.DLL用来实现与模拟器或设备进行交互.现在针对原有解决方案添加一个命名为DeveiceAutomationTest_Desktop的Console类型应用程序用来做回归测试自动化的控制台.解决方案结构如下:

    要实现对模拟器交互控制 需要在控制台应用程序添加对Microsoft.SmartDevice.Connectivity.DLL引用,引用地址C:\Program Files (x86)\Common Files\microsoft shared\Phone Tools\CoreCon\10.0\Bin:

添加引用后,实现对应设备控制的操作.连接并安装初始化XAP到模拟器中,添加一个设备控制类DeviceManager类,首先要根绝设备类型模拟器或真机获取设备的控制设备的Device对象:

 


   
   
  1. /// <summary>     
  2. /// Get Current Support Platform Device Object     
  3. /// </summary>     
  4. /// <param name="localId">Region Local Id</param>     
  5. /// <returns>Device Object</returns>     
  6. public static Device GetSupportPlatformDeviceObj(int localId,bool isDevice)     
  7. {     
  8.     //Note By chenkai:     
  9.     //1033 is the LCID for English, United States and 1031 is the LCID for German, Germany.   
  10.     //Please Check List of Locale ID (LCID) Values as Assigned by Microsoft.    
  11.     //http://msdn.microsoft.com/zh-cn/goglobal/bb964664.aspx    
  12.     //Now Use English is 1031    
  13.     if (localId == 0)    
  14.         localId = 1031;    
  15.     Device currentDeviceObj = null;    
  16.     DatastoreManager datastoreManagerObj = new DatastoreManager(localId);    
  17.     Platform wp7Platform = datastoreManagerObj.GetPlatforms().Single(p => p.Name == "Windows Phone 7");    
  18.     if (wp7Platform != null)    
  19.     {    
  20.         if (isDevice)    
  21.             currentDeviceObj = wp7Platform.GetDevices().Single(x => x.Name == "Windows Phone Device");    
  22.         else    
  23.             currentDeviceObj = wp7Platform.GetDevices().Single(x => x.Name == "Windows Phone Emulator");    
  24.     }    
  25.     return currentDeviceObj;    

    localid是在初始化静态 DatastoreManager 对象时是一个区域设置标识符 (LCID),这是一个标识语言、国家和/或地区的整数. 当然这里采用1031德国地区.针对这个区域Localid的设置请参考官方给出的List of Locale ID (LCID) Values as Assigned by Microsoft 列表.

    获取数据控制Device对象后.可以连接设备并把XAP包安装并初始化到设备中:


   
   
  1. /// <summary>     
  2. /// Connection Emulator Device     
  3. /// </summary>     
  4. /// <param name="deviceObj">Device Object</param>     
  5. /// <param name="applicationGuid">Application Guid</param>     
  6. /// <param name="iconFilePath">IconFile Path</param>     
  7. /// <param name="xapFileName">XapFile Name</param>     
  8. /// <returns>return is Connection Device</returns>     
  9. public static void ConnectionDeviceInstallApp(Device deviceObj,Guid applicationGuid,string iconFilePath,string xapFileName)    
  10. {    
  11.     if (!string.IsNullOrEmpty(applicationGuid.ToString()))    
  12.     {    
  13.         try    
  14.         {    
  15.             deviceObj.Connect();    
  16.            ApplicationManager.InstallApplicationAndLaunch(deviceObj, applicationGuid, iconFilePath, xapFileName);    
  17.         }    
  18.         finally    
  19.         {    
  20.             deviceObj.Disconnect();    
  21.         }    
  22.     }    

    这个方法中需要提供Device设备操作对象.以及XAP安装包和对应应用程序图标的文件路径. 其实这里并不一定非得采用控制台的方式.也可以做一个Winform以可见UI的方式.至于Guid则是测试项目WP7AutomationTest_Demo.Test-WMAppmainfest.xml文件中的ProductId相对应:


   
   
  1. <App xmlns="" ProductID="{b81d87a6-3afd-4f21-9a60-3c5ae0921fd2}" Title="WP7AutomationTest_Demo.Test"/> 

    该方法中执行了两个操作.链接设备.安装XAP包到设备中.安装XAP操作通过ApplicationManager类中InstallApplicationAndLaunch方法 .定义如下:


   
   
  1. public static void InstallApplicationAndLaunch(Device deviceObj, Guid applicationGuid, string iconFileName, string xapFileName)     
  2. {     
  3.     if (!string.IsNullOrEmpty(applicationGuid.ToString()))     
  4.     {     
  5.         //Install and Luanch     
  6.         UnstallApplicationAndClear(deviceObj, applicationGuid);     
  7.         deviceObj.InstallApplication(applicationGuid, applicationGuid, "AutomationAPP", iconFileName, xapFileName);     
  8.         RemoteApplication currentApplication = deviceObj.GetApplication(applicationGuid);     
  9.         if (currentApplication != null)    
  10.             currentApplication.Launch();    
  11.     }    

    通过Device对象初始化XAP 并Lauch,.在执行安装XAP之前 如果正在运行则立即中断.如果已经安装该应用程序则需删除卸载:


   
   
  1. public static void UnstallApplicationAndClear(Device deviceObj, Guid applicationGuid)     
  2. {     
  3.     if(!string.IsNullOrEmpty(applicationGuid.ToString()))     
  4.     {     
  5.         if (deviceObj.IsApplicationInstalled(applicationGuid))     
  6.         {     
  7.             RemoteApplication remoteApplication = deviceObj.GetApplication(applicationGuid);     
  8.             if (remoteApplication != null)     
  9.             {    
  10.                 //Remove Application    
  11.               remoteApplication.TerminateRunningInstances();    
  12.                 remoteApplication.Uninstall();    
  13.             }    
  14.         }    
  15.     }    

    well.如此封装号对设备的初始化的控制.开始执行ProgramMain 方法:


   
   
  1. static void Main(string[] args)     
  2. {     
  3.     //Base ApplicationInfo     
  4.     string xapfile = @"..\..\..\WP7AutomationTest_Demo.Test\Bin\Debug\WP7AutomationTest_Demo.Test.xap";     
  5.     string iconfile = @"..\..\..\WP7AutomationTest_Demo.Test\Bin\Debug\WApplicationIcon.png";     
  6.     ApplicationBaseInfo currentBaseInfo = new ApplicationBaseInfo(xapfile, iconfile, new Guid("b81d87a6-3afd-4f21-9a60-3c5ae0921fd2"));     
  7.     //DeviceManager Object     
  8.     Device deviceObj = DeviceManager.GetSupportPlatformDeviceObj(1031,false);    
  9.     using (ServiceHost currentHost = new ServiceHost(typeof(TestResultReportService)))    
  10.     {    
  11.         currentHost.Open();  13:                  Console.WriteLine("Current Service is Open...");    
  12.         Console.WriteLine("Connecting to Windows phone Emluator Device...");   
  13.         try    
  14.         {    
  15.             //Device Connection    
  16.             deviceObj.Connect();    
  17.             Console.WriteLine("Windows phone Emluator Device Connected...");    
  18.            ApplicationManager.InstallApplicationAndLaunch(deviceObj, currentBaseInfo.ApplicationGuid, currentBaseInfo.IconFilePath, currentBaseInfo.XapFilePath);    
  19.             Console.WriteLine("Wait For Run TestCase Compated...");       
  20.             lastendTestRunEvent.WaitOne(12000);       
  21.             Console.WriteLine("Test Case is Run Complate...");    
  22.             ApplicationManager.UnstallApplicationAndClear(deviceObj, currentBaseInfo.ApplicationGuid);    
  23.             Console.WriteLine("Application is UnStall and Clear...");                       
  24.         }    
  25.         finally    
  26.         {    
  27.             deviceObj.Disconnect();    
  28.         }    
  29.         //currentHost.Close();    
  30.     } 

    Main方法执行的流程.首先部署XAP停止正在应用程序.并从设备中移除.然后连接设备 部署XAP包. 执行TEstCase测试用例.获取测试用例反馈结果.卸载当前应用程序并清空数据状态.回复测试运行前.测试效果:

    正常运行时如果模拟器没有运行会自动打开模拟器 安装XAP包运行测试用例.当控制台获取测试结果后.卸载当前当前测试用例.一个完整回归测试流程就建立成功了.而发现可以把整个执行流程全部自动化代码控制.当然可以把回归测试在执行多条数据时多次自动化执行.整个执行流程控制台操作如下:

    在main方法同时建立一个WCF服务.该服务的主要目的是在单元测试用例测试完成后通知控制台停止调用. 另外一个目的是把SUTF框架的测试结果传递给控制台.存在一个测试结果文件中保存在本地并输出到控制台中:


   
   
  1. public class TestResultReportService : ITestResultReportService     
  2. {     
  3.     public void SaveTestResultFile(string filename, string filecontent)     
  4.     {     
  5.         var outputfile = Path.Combine(@"..\..\..\DeveiceAutomationTest_Desktop\Bin\Debug\", filename);     
  6.         if (File.Exists(outputfile))     
  7.         {     
  8.             File.Delete(outputfile);     
  9.         }    
  10.         File.WriteAllText(outputfile, filecontent);    
  11.         Console.WriteLine(filecontent);    
  12.     }          
  13.     public void GetFinalTestResult(bool failure, int failures, int totalScenarios, string message)    
  14.     {    
  15.         Console.WriteLine(message);    
  16.         Program.EndTestRun();    
  17.     }    

    而针对测试用例应用程序WP7AutomationTest_Demo.Test需要额外引用该服务.重新建立一个TestBaseReportService类用来重写TestReportingProvider实体类中方法实现.测试结果通过服务以消息的形式传递给控制台.保存在文件中: 首先添加引用:


   
   
  1. using Microsoft.Silverlight.Testing;     
  2. using Microsoft.Silverlight.Testing.Harness;     
  3. using Microsoft.Silverlight.Testing.Service;     
  4. using Microsoft.VisualStudio.TestTools.UnitTesting; 

重写方法: 


   
   
  1. public class TestBaseReportService:TestReportingProvider     
  2. {     
  3.     //ServiceClient     
  4.     UnitTestService.TestResultReportServiceClient reportClient = new UnitTestService.TestResultReportServiceClient();     
  5.     public TestBaseReportService(TestServiceProvider serviceProvider) : base(serviceProvider) { }     
  6.  
  7.     public override void ReportFinalResult(Action<ServiceResult> callback, bool failure, int failures, int totalScenarios, string message)     
  8.     {     
  9.         this.IncrementBusyServiceCounter();    
  10.         reportClient.SaveTestResultFileCompleted += (se, x) =>    
  11.         {  12:                  this.DecrementBusyServiceCounter();    
  12.         };    
  13.         reportClient.GetFinalTestResultAsync(failure, failures, totalScenarios, message);    
  14.         base.ReportFinalResult(callback, failure, failures, totalScenarios, message);    
  15.     }    
  16.  
  17.     public override void WriteLog(Action<ServiceResult> callback, string logName, string content)    
  18.     {    
  19.         this.IncrementBusyServiceCounter();    
  20.         reportClient.SaveTestResultFileCompleted += (s, e) =>    
  21.         {    
  22.             this.DecrementBusyServiceCounter();    
  23.         };    
  24.         reportClient.SaveTestResultFileAsync(logName, content);    
  25.         base.WriteLog(callback, logName, content);    
  26.     }    

    ok。定义重写服务之后还需要Silverlight Unit TESt FrameWork框架进行测试结果的关联.这很关键.SUTF框架将通过该服务来提交报告. 在mainpage定义输出的页面添加如下Code:


   
   
  1. var reportSetting = UnitTestSystem.CreateDefaultSettings();     
  2.  if (reportSetting!=null)     
  3.  {     
  4.      reportSetting.TestService.RegisterService(TestServiceFeature.TestReporting, new TestBaseReportService(reportSetting.TestService));     
  5.  } 

    一整个回归测试自动化流程建立完毕",编译通过执行:

    well.可以看到把整个回归测试整个流程完全自动化用Code处理了. 而控制台应用就类似自动化时可以复用处理的脚本一样.可以复用.依然能够看到控制台中存在几个需要及时制定的变量类似.XAP 包路径等.也可以封装可见的UI指定.当我们修改审核玩测试用例后.就可以通过该控制台应用程序.定期执行自动化回归的测试.生成测试报告.很有效保证代码集成时质量.本篇只是提供自动化解决一种方案.

    源代码见附件。

 

    首先来看看应用程序安装执行过程.目前只能通过Application Development Tool部署真机上: