一个基于.NET平台的自动化/压力测试系统设计简述

AutoTest系统设计概述

AutoTest是一个基于.NET平台实现的自动化/压力测试的系统,可独立运行于windows平台下,支持分布式部署,不需要其他配置或编译器的支持。(本质是一个基于协议的测试工具),前面还有一篇对其功能的简单介绍【AutoTest简介】

AutoTest用于发布的部分有2个部分,主程序【AutoTest.exe】及分布式部署程序【RemoteService.exe】(用于将将测试业务分布式部署到远程主机)

而在内部又被设计为多个组成部分,最终完成对自定义脚本文件的解析并按脚本要求的模式去执行。

一个基于.NET平台的自动化/压力测试系统设计简述_第1张图片

 

如上图,简单介绍下

执行逻辑层主要由3部分组成

  • MyControl.dll                       该部分主要为表示层提供专门为业务定制的UI控件等用于显示数据的组件
  • myCommonTool.dll                  该部分为这个解决方案即这个系统提供通用的工具方法及组件如日志系统(指系统本身的日子系统,测试过程中的日志或记录由专门的记录采集模块完成)
  • CaseExecutiveActuator.dll       该部分为这个测试平台提供最核心的逻辑处理部分,如脚本的解析,脚本的选择,脚本的执行等(对于系统来说添加任意的其他的协议支持也仅需要修改这个库中的部分内容)

表示层暂时是由2部分组成

  • AutoTest.exe                            测试平台显示界面,运行于windows环境下,赋值数据及结果的呈现,同时负责与操作者者进行交换
  • RemoteService.exe                  分布式部署程序,负责在远程主机开启服务实现测试任务的分布式部署,分布式远程服务基于WCF框架理论上支持跨internet的分布式部署

最下面的2个模块是用于系统内部模块的单元测试,本身与系统运行无关,所以就不赘述了

 

此外还有一个重要的组成部分-脚本文件,这里使用的脚本依托于XML文件,规则上基本是独立定义的。脚本文件控制所有Case的执行方式,内容,甚至是执行路径,还包括对断言的额外处理。脚本文件被解释器(CaseExecutiveActuator的一部分)转换为系统/工具直接可以使用的数据结构,并最终被执行。(脚本规则相对独立,将不会在此篇中涉及)

 

核心执行模块【CaseExecutiveActuator】

 

CaseExecutiveActuator模块主要由2部分组成,脚本处理部分(算法)及脚本内容的存储部分(数据)。

脚本对外的存在形式是XML文件,这个XML也是最终的脚本文件。系统解析这个XML文件(对CASE内容,或测试业务的修改包括新建也只是对XML脚本文件的修改而),然后对其进行进一步处理(当然使用合适的数据结构对其进行存储是第一步)。脚本的存储比较简单,先看这部分,其实就是实现了一个类似Tree的数据结构来存储整个脚本逻辑,然后每个单独的Case都存储在单独的Cell里(Cell为该自定义数据结构的基础单元,于单个Case对应)。

Cell的结构如下(简单的实现了形如右边图片的的数据结构)

一个基于.NET平台的自动化/压力测试系统设计简述_第2张图片                          一个基于.NET平台的自动化/压力测试系统设计简述_第3张图片

 

其实很容易看出来这个结构跟TreeView的结构十分类似,其实最初脚本数据的存储是直接借助于TreeView的,不过为了将业务跟UI完全分离以便未来向其他平台移植时不受UI框架的影响,还是自行实现了这样的数据结构。Cell结构本身十分简单,有3个主要的结构指针

childCellList    指向子Cell

nextCell          指向下一个Cell

parentCell       指向父Cell

还有2个数据源

caseXmlNode      指向元素的脚本数据,保留原始数据的地址是为了方便AutoTest对脚本的直接修改(这里使用的XML,如果希望相关脚本文件类型需要修改此处及脚本解析部分)

caseRunData       已经解析完成的单Case数据(实际加载脚步时对所有脚本解析一次,把结果存储在这里,后面的执行即直接取这里的数据以提高性能)

另外包含2个辅助元素

caseType            指示该Cell即Case的实类型,可以辅助处理异常Cell的数据。

uiTag                  可选的指针,用于数据绑定,名字也提示了主要用于绑定UI(实际可用绑定任何类型的数据)

该机构还提供一些其他功能如Cell的容器及索引器等有兴趣的可以看下下面的Code

 

  1 /*******************************************************************************
  2 * Copyright (c) 2015 lijie
  3 * All rights reserved.
  4 * 
  5 * 文件名称: 
  6 * 内容摘要: [email protected]
  7 * 
  8 * 历史记录:
  9 * 日      期:   201505016           创建人: [email protected]
 10 * 描    述: 创建
 11 *******************************************************************************/
 12 
 13 namespace CaseExecutiveActuator.Cell
 14 {
 15     //using CaseCell = TreeNode;//可让2类完全等价
 16     public class CaseCell 
 17     {
 18         List childCellList;
 19 
 20         private CaseType caseType;
 21         private XmlNode caseXmlNode;
 22         private myRunCaseData caseRunData;
 23         private object uiTag;
 24 
 25         private CaseCell nextCell;
 26         private CaseCell parentCell;
 27         
 28 
 29         public CaseCell()
 30         {
 31 
 32         }
 33 
 34         /// 
 35         /// CaseCell构造函数
 36         /// 
 37         /// CaseType
 38         /// CaseCell脚本原始信息
 39         /// CaseCell脚本解析后的信息
 40         public CaseCell(CaseType yourCaseType, XmlNode yourXmlNode ,myRunCaseData yourCaseRunData)
 41         {
 42             caseType = yourCaseType;
 43             caseXmlNode = yourXmlNode;
 44             caseRunData = yourCaseRunData;
 45         }
 46 
 47         /// 
 48         /// 获取或设置CaseCell脚本解析后的信息
 49         /// 
 50         public myRunCaseData CaseRunData
 51         {
 52             get { return caseRunData; }
 53             set { caseRunData = value; }
 54         }
 55 
 56         /// 
 57         /// 获取或设置CaseCell脚本原始信息
 58         /// 
 59         public XmlNode CaseXmlNode
 60         {
 61             get { return caseXmlNode; }
 62             set { caseXmlNode = value; }
 63         }
 64 
 65         /// 
 66         /// 获取或设置UiTag,可以用于UI控件与cell的绑定
 67         /// 
 68         public object UiTag
 69         {
 70             get { return uiTag; }
 71             set { uiTag = value; }
 72         }
 73 
 74         /// 
 75         /// 获取当前Cell类型
 76         /// 
 77         public CaseType CaseType
 78         {
 79             get { return caseType; }
 80         }
 81 
 82         /// 
 83         /// 获取下一个Cell,如果没有返回null
 84         /// 
 85         public CaseCell NextCell
 86         {
 87             get { return nextCell; }
 88         }
 89 
 90         /// 
 91         /// 获取当前Cell的父Cell,如果没有返回null
 92         /// 
 93         public CaseCell ParentCell
 94         {
 95             get { return parentCell; }
 96         }
 97 
 98         /// 
 99         /// 获取当前Cell的ChildCells列表
100         /// 
101         public List ChildCells
102         {
103             get { return childCellList; }
104         }
105 
106         /// 
107         /// 获取一个值标识当前Cell是否有NextCell
108         /// 
109         public bool IsHasNextCell
110         {
111             get { return nextCell != null; }
112         }
113 
114         /// 
115         /// 获取一个值标识当前Cell是否有parentCell
116         /// 
117         public bool IsHasParent
118         {
119             get
120             {
121                 if (parentCell != null)
122                 {
123                     return true;
124                 }
125                 return false;
126             }
127         }
128 
129         /// 
130         /// 获取一个值标识当前Cell是否有ChildCell
131         /// 
132         public bool IsHasChild
133         {
134             get
135             {
136                 if (childCellList != null)
137                 {
138                     if (childCellList.Count != 0)
139                     {
140                         return true;
141                     }
142                 }
143                 return false;
144             }
145         }
146 
147         /// 
148         /// 设置下一个Cell
149         /// 
150         /// 下一个Cell
151         public void SetNextCell(CaseCell yourCaseCell)
152         {
153             nextCell = yourCaseCell;
154         }
155 
156         /// 
157         /// 设置ParentCell
158         /// 
159         /// ParentCell
160         public void SetParentCell(CaseCell yourCaseCell)
161         {
162             parentCell = yourCaseCell;
163         }
164 
165         /// 
166         /// 向当前Cell中插入子Cell
167         /// 
168         /// 子Cell
169         public void Add(CaseCell yourCaseCell)
170         {
171             if (childCellList == null)
172             {
173                 childCellList = new List();
174             }
175             yourCaseCell.SetParentCell(this);
176             childCellList.Add(yourCaseCell);
177             if(childCellList.Count>1)
178             {
179                 childCellList[childCellList.Count-2].SetNextCell(yourCaseCell);
180             }
181         }
182 
183         //一个tag存放ui指针/引用
184         //实现一个Nodes.Count计算每层数目,或返回是否有子结构
185         //Nodes[0]索引或实现NodeStart,返回层中第一个CaseCell
186         //实现一个NextNode返回层中的下一个CaseCell
187     }
188 
189     public class ProjctCollection
190     {
191         List myProjectChilds;
192 
193         public List ProjectCells
194         {
195             get { return myProjectChilds; }
196         }
197 
198         public void Add(CaseCell yourCaseCell)
199         {
200             if (myProjectChilds == null)
201             {
202                 myProjectChilds = new List();
203             }
204             myProjectChilds.Add(yourCaseCell);
205         }
206 
207         public CaseCell this[int indexP, int indexC]
208         {
209             get
210             {
211                 if(myProjectChilds.Count>indexP)
212                 {
213                     if (myProjectChilds[indexP].IsHasChild)
214                     {
215                         if (myProjectChilds[indexP].ChildCells.Count > indexC)
216                         {
217                             return myProjectChilds[indexP].ChildCells[indexC];
218                         }
219                     }
220                 }
221                 return null;
222             }
223         }
224 
225         
226     }
227 }
View Code

 

执行的实体CaseExecutiveActuator本身会较多点,介绍的也会粗略些,不过大体也是可以简单的分成2个部分。可以很容易的想到假如我们得了脚本文件,那么有2个问题:第一就是怎么知道选择哪一个case,当前case执行完成后执行哪一个,第二个问题就是case中包含的业务如何执行。CaseExecutiveActuator也正是分成了这2部分

  • myCaseRunTime                                  负责指引Case路径,Cell的寻找,跳转及序列的指示 都是由它完成的
  • CaseActionActuator                             负责Case的具体执行,包括对各种协议的执行,及对结果的分析及储存,断言的处理,附加动作如语音提示,重试等执行相关的部分就由它处理

先来看比较简单的CaseRunTime   

一个基于.NET平台的自动化/压力测试系统设计简述_第4张图片

 

实际上于CaseRunTime  紧密相关的还有另外2个组件myCaseLoop,myCsaeQueue(他们实际上也仅被CaseRunTime 使用)

通过名字其实大概可以猜到他们的功能

  • myCaseLoop                                 控制一组Case(可以是由多个Case组成的业务)的循环执行,当然支持循环里无限嵌套其他的循环
  • myCsaeQueue                          控制一个逻辑项目的Case坐标(当前执行的Case),基础的Case会放在一个个逻辑项目中,每个逻辑下项目可以标识一类业务的集合,而当前执行Case是可以在这些逻辑项目中来回跳转的,所以它负责多个逻辑项目的寻址
  • myCaseRunTime                           借助前面的CaseLoop 和  CsaeQueue,完成整个Case的移动轨迹(这个轨迹可能因执行结果不同而有不同的变化,取决于脚本文件如何写)
  • RunCaseCount                              一个辅助类,帮助统计脚本中实际将要执行的Case数量(会考虑起始点及循环等因素)                      

单独看看myCaseRunTime

一个基于.NET平台的自动化/压力测试系统设计简述_第5张图片

如上图可以看到myCaseRunTime实际上是包含了一个myCsaeQueue列表的,不过逻辑的核心是nextCase。有兴趣的可以看看下面的实现(贴出的只包含关键部分)

  1  class RunCaseCount
  2     {
  3         /// 
  4         /// for count strut
  5         /// 
  6         struct CaseLoopCountInfo
  7         {
  8             CaseCell loopNode;
  9             int caseRate;
 10 
 11             /// 
 12             /// Initialization the CaseLoopCountInfo
 13             /// 
 14             /// your LoopNode
 15             /// your CaseRate
 16             public CaseLoopCountInfo(CaseCell yourLoopNode, int yourCaseRate)
 17             {
 18                 loopNode = yourLoopNode;
 19                 caseRate = yourCaseRate;
 20             }
 21 
 22             /// 
 23             /// get the LoopNode
 24             /// 
 25             public CaseCell LoopNode
 26             {
 27                 get { return loopNode; }
 28             }
 29 
 30             /// 
 31             /// get the CaseRate
 32             /// 
 33             public int CaseRate
 34             {
 35                 get { return caseRate; }
 36             }
 37         }
 38 
 39 
 40         /// 
 41         /// get main task case count(just main but not Include the goto case)
 42         /// 
 43         /// start Node
 44         /// count
 45         public static int GetCount(CaseCell startNode)
 46         {
 47             int nowCount = 0;
 48             List nowLoops = new List();
 49             while (startNode!=null)
 50             {
 51                 if (startNode.CaseType == CaseType.Case)
 52                 {
 53                     nowCount++;
 54                 }
 55                 else if (startNode.CaseType == CaseType.Repeat)
 56                 {
 57                     if (startNode.IsHasChild)
 58                     {
 59                         myCaseLaodInfo tempProjectLoadInfo = myCaseScriptAnalysisEngine.getCaseLoadInfo(startNode.CaseXmlNode);
 60                         nowLoops.Add(new CaseLoopCountInfo(startNode.ChildCells[0], tempProjectLoadInfo.times));
 61                     }
 62                 }
 63                 else if (startNode.CaseType == CaseType.Project)
 64                 {
 65                     if(startNode.IsHasChild)
 66                     {
 67                         startNode = startNode.ChildCells[0];
 68                     }
 69                     continue;
 70                 }
 71                 startNode = startNode.NextCell;
 72             }
 73             while (nowLoops.Count!=0)
 74             {
 75                 startNode = nowLoops[nowLoops.Count - 1].LoopNode;
 76                 int tempRate = nowLoops[nowLoops.Count - 1].CaseRate;
 77                 nowLoops.Remove(nowLoops[nowLoops.Count - 1]);
 78                 while (startNode != null)
 79                 {
 80                     if (startNode.CaseType == CaseType.Case)
 81                     {
 82                         nowCount += tempRate;
 83                     }
 84                     else if (startNode.CaseType == CaseType.Repeat)
 85                     {
 86                         if (startNode.IsHasChild)
 87                         {
 88                             myCaseLaodInfo tempProjectLoadInfo = myCaseScriptAnalysisEngine.getCaseLoadInfo(startNode.CaseXmlNode);
 89                             nowLoops.Add(new CaseLoopCountInfo(startNode.ChildCells[0], tempProjectLoadInfo.times * tempRate));
 90                         }
 91                     }
 92                     startNode = startNode.NextCell;
 93                 }
 94             }
 95             return nowCount;
 96         }
 97 
 98 
 99     }
100 
101 
102     /// 
103     /// CsaeQueue it will only used in myCaseRunTime
104     /// 
105     class myCsaeQueue
106     {
107         private CaseCell startCaseNode;
108         private CaseCell nowCaseNode;
109         List myCaseLoopList;
110 
111         private int queueTotalCount;
112         private int queueNowCount;
113 
114         public event delegateLoopChangeEventHandler OnLoopChangeEvent;
115 
116         /// 
117         /// myCsaeQueue initialize
118         /// 
119         /// your StartCase and make sure it is not null
120         public myCsaeQueue(CaseCell yourStartCase)
121         {
122             queueTotalCount = RunCaseCount.GetCount(yourStartCase);
123             startCaseNode = yourStartCase;
124             nowCaseNode = null;
125             myCaseLoopList = new List();
126         }
127 
128         /// 
129         /// get now CaseCell
130         /// 
131         public CaseCell NowCaseNode
132         {
133             get
134             {
135                 if (nowCaseNode != null)
136                 {
137                     if (myCaseLoopList.Count > 0)
138                     {
139                         return myCaseLoopList[myCaseLoopList.Count - 1].NowCaseNode;
140                     }
141                     else
142                     {
143                         return nowCaseNode;
144                     }
145                 }
146                 else
147                 {
148                     return startCaseNode;
149                 }
150             }
151         }
152 
153         /// 
154         /// get the Queue Count Progress(queueTotalCount and queueNowCount)
155         /// 
156         public KeyValuePair<int,int> GetCountProgress
157         {
158             get
159             {
160                 return new KeyValuePair<int, int>(queueTotalCount, queueNowCount);
161             }
162         }
163 
164         
165         /// 
166         /// i will add new CaseLoop and Subscribe 【OnLoopChangeEvent】
167         /// 
168         /// your StartCase
169         /// your Times
170         private void AddCaseLoop(CaseCell yourStartCase, int yourTimes)
171         {
172             myCaseLoopList.Add(new myCaseLoop(yourStartCase, yourTimes));
173             myCaseLoopList[myCaseLoopList.Count - 1].OnLoopChangeEvent += OnLoopChangeEvent;
174         }
175 
176         /// 
177         /// i will remove your CaseLoop and unSubscribe 【OnLoopChangeEvent】
178         /// 
179         /// yourCaseLoop
180         private void DelCaseLoop(myCaseLoop yourCaseLoop)
181         {
182             yourCaseLoop.OnLoopChangeEvent -= OnLoopChangeEvent;
183             myCaseLoopList.Remove(yourCaseLoop);
184         }
185 
186 
187         /// 
188         /// i will get the next myTreeTagInfo in my queue
189         /// 
190         /// the CaseCell you want
191         public CaseCell nextCase()
192         {
193            
194             if(nowCaseNode==null) //起始节点
195             {
196                 nowCaseNode = startCaseNode;
197                 if (nowCaseNode.CaseType == CaseType.Repeat)
198                 {
199                     if (nowCaseNode.IsHasChild)
200                     {
201                         myCaseLaodInfo tempProjectLoadInfo = myCaseScriptAnalysisEngine.getCaseLoadInfo(nowCaseNode.CaseXmlNode);
202                         AddCaseLoop(nowCaseNode.ChildCells[0], tempProjectLoadInfo.times);
203                     }
204                     return nextCase();
205                 }
206                 else if (nowCaseNode.CaseType == CaseType.Case)
207                 {
208                     queueNowCount++;
209                     return nowCaseNode;
210                 }
211                 else if (nowCaseNode.CaseType == CaseType.Project)
212                 {
213                     if (nowCaseNode.IsHasChild)
214                     {
215                         startCaseNode = nowCaseNode.ChildCells[0];
216                         nowCaseNode = null;
217                         return nextCase();
218                     }
219                     return null; //空Project
220                 }
221                 else
222                 {
223                     return null; //当前设计不会有这种情况
224                 }
225             }
226             else
227             {
228                 if (myCaseLoopList.Count > 0)
229                 {
230                     int tempNowListIndex = myCaseLoopList.Count - 1;
231                     CaseCell tempNextLoopTreeNode = myCaseLoopList[tempNowListIndex].nextCase();
232                     if (tempNextLoopTreeNode == null)
233                     {
234                         DelCaseLoop(myCaseLoopList[tempNowListIndex]);
235                         return nextCase();
236                     }
237                     else
238                     {
239                         if (tempNextLoopTreeNode.CaseType == CaseType.Repeat)
240                         {
241                             if (tempNextLoopTreeNode.IsHasChild)
242                             {
243                                 myCaseLaodInfo tempProjectLoadInfo = myCaseScriptAnalysisEngine.getCaseLoadInfo(tempNextLoopTreeNode.CaseXmlNode);
244                                 AddCaseLoop(tempNextLoopTreeNode.ChildCells[0], tempProjectLoadInfo.times);
245                             }
246 
247                             return nextCase();
248                         }
249                         else if (tempNextLoopTreeNode.CaseType == CaseType.Case)
250                         {
251                             queueNowCount++;
252                             return tempNextLoopTreeNode;
253                         }
254                         else
255                         {
256                             return null; //当前设计不会有这种情况
257                         }
258                     }
259                 }
260                 else
261                 {
262                     if(nowCaseNode.NextCell == null)
263                     {
264                         return null; //当前 【Queue】 结束
265                     }
266                     else
267                     {
268                         nowCaseNode = nowCaseNode.NextCell;
269                         if (nowCaseNode.CaseType == CaseType.Repeat)
270                         {
271                             if (nowCaseNode.IsHasChild)
272                             {
273                                 myCaseLaodInfo tempProjectLoadInfo = myCaseScriptAnalysisEngine.getCaseLoadInfo(nowCaseNode.CaseXmlNode);
274                                 AddCaseLoop(nowCaseNode.ChildCells[0], tempProjectLoadInfo.times);
275                             }
276 
277                             return nextCase();
278                         }
279                         else if (nowCaseNode.CaseType == CaseType.Case)
280                         {
281                             queueNowCount++;
282                             return nowCaseNode;
283                         }
284                         else
285                         {
286                             return null; //当前设计不会有这种情况
287                         }
288                     }
289                 }
290             }
291         }
292 
293     }
294 
295     /// 
296     /// CaseLoop it will only used in myCsaeQueue
297     /// 
298     class myCaseLoop
299     {
300         private CaseCell startCaseNode;
301         private CaseCell nowCaseNode;
302         private int totalTimes;
303         private int myTimes;
304 
305         public event delegateLoopChangeEventHandler OnLoopChangeEvent;
306 
307         /// 
308         /// myCaseLoop initialize
309         /// 
310         /// your StartCase and make sure it is not null
311         /// your Times 
312         public myCaseLoop(CaseCell yourStartCase, int yourTimes)
313         {
314             totalTimes = myTimes = yourTimes;
315             startCaseNode = yourStartCase;
316             nowCaseNode = null;
317         }
318 
319         /// 
320         /// get now CaseCell
321         /// 
322         public CaseCell NowCaseNode
323         {
324             get
325             {
326                 if (nowCaseNode != null)
327                 {
328                     return nowCaseNode;
329                 }
330                 else
331                 {
332                     return startCaseNode;
333                 }
334             }
335         }
336 
337         /// 
338         /// i will trigger 【OnLoopChangeEvent】
339         /// 
340         /// 
341         private void ReportLoopProgress(CaseCell yourTarget)
342         {
343             if (OnLoopChangeEvent != null)
344             {
345                 OnLoopChangeEvent(yourTarget.ParentCell, string.Format("{0}/{1}", totalTimes, totalTimes - myTimes + 1));
346             }
347         }
348 
349         /// 
350         /// i will trigger 【OnLoopChangeEvent】 and this lood is end
351         /// 
352         /// 
353         private void ReportLoopEnd(CaseCell yourTarget)
354         {
355             if (OnLoopChangeEvent != null)
356             {
357                 this.OnLoopChangeEvent(yourTarget.ParentCell, "");
358             }
359         }
360         
361         /// 
362         /// i will get the next myTreeTagInfo in my loop
363         /// 
364         /// the CaseCell you want
365         public CaseCell nextCase()
366         {
367             if (myTimes > 0)
368             {
369                 if (nowCaseNode == null) //起始节点
370                 {
371                     nowCaseNode = startCaseNode;
372                     //report position
373                     ReportLoopProgress(nowCaseNode);
374                     return nowCaseNode;
375                 }
376                 else
377                 {
378                     if (nowCaseNode.NextCell == null)
379                     {
380                         myTimes--;
381                         if (myTimes > 0)
382                         {
383                             nowCaseNode = startCaseNode;
384                             ReportLoopProgress(nowCaseNode);
385                             return nowCaseNode;
386                         }
387                         else
388                         {
389                             ReportLoopEnd(nowCaseNode);
390                             return null;   //此处为null,指示当前【Loop】结束
391                         }
392 
393                     }
394                     else
395                     {
396                         nowCaseNode = nowCaseNode.NextCell;
397                         return nowCaseNode;    //此处caseType可能为case或repeat,该类的拥有者将会分别处理
398                     }
399                 }
400             }
401             else
402             {
403                 return null;
404             }
405         }
406     }
407     
408     /// 
409     /// myCaseRunTime - you can get next case here
410     /// 
411     public sealed class myCaseRunTime
412     {
413         
414         private List myCsaeQueueList;
415         private bool isThroughAllCase;
416 
417         /// 
418         /// show loop track 
419         /// 
420         public event delegateLoopChangeEventHandler OnLoopChangeEvent;
421         /// 
422         /// show Queue track (the frist and last Queue will nor trigger)
423         /// 
424         public event delegateQueueChangeEventHandler OnQueueChangeEvent;
425 
426         /// 
427         /// myCaseRunTime initialize
428         /// 
429         public myCaseRunTime()
430         {
431             myCsaeQueueList = new List();
432         }
433 
434         /// 
435         /// get now CaseRunTime all Progress
436         /// 
437         public Listint ,int >> GetNowCountProgress
438         {
439             get
440             {
441                 Listint, int>> nowCountProgress = new Listint, int>>();
442                 foreach (var tempCsaeQueue in myCsaeQueueList)
443                 {
444                     nowCountProgress.Add(tempCsaeQueue.GetCountProgress);
445                 }
446                 return nowCountProgress;
447             }
448         }
449 
450         /// 
451         /// i will add new CsaeQueue and Subscribe 【OnLoopChangeEvent】
452         /// 
453         /// your CsaeQueue that will add
454         private void AddCsaeQueue(myCsaeQueue yourCsaeQueue)
455         {
456             myCsaeQueueList.Add(yourCsaeQueue);
457             yourCsaeQueue.OnLoopChangeEvent += OnLoopChangeEvent;
458         }
459 
460         //// 
461         /// i will add new CsaeQueue and Subscribe 【OnLoopChangeEvent】(and will trigger【OnQueueChangeEvent】)
462         /// 
463         /// your CsaeQueue that will add
464         /// Project Id to OnQueueChangeEvent
465         /// Case Id to OnQueueChangeEvent
466         private void AddCsaeQueue(myCsaeQueue yourCsaeQueue, int yourProjectId, int yourCaseId)
467         {
468             ReportQueueAction(myCsaeQueueList[myCsaeQueueList.Count - 1].NowCaseNode, string.Format("▼GoTo Project:{0} Case:{1}", yourProjectId, yourCaseId));
469             AddCsaeQueue(yourCsaeQueue);
470             ReportQueueAction(myCsaeQueueList[myCsaeQueueList.Count - 1].NowCaseNode, "");
471         }
472 
473         /// 
474         /// i will remove the CaseQueue and unSubscribe 【OnLoopChangeEvent】
475         /// 
476         /// your CsaeQueue that will rwmove
477         private void DelCsaeQueue(myCsaeQueue yourCsaeQueue)
478         {
479             if (myCsaeQueueList.Count>1)
480             {
481                 ReportQueueAction(yourCsaeQueue.NowCaseNode, "");
482                 ReportQueueAction(myCsaeQueueList[myCsaeQueueList.Count - 2].NowCaseNode, "▼▲");
483             }
484             yourCsaeQueue.OnLoopChangeEvent -= OnLoopChangeEvent;
485             myCsaeQueueList.Remove(yourCsaeQueue);
486         }
487 
488 
489         /// 
490         /// i will report the QueueAction to his user 
491         /// 
492         /// your CaseCell Target
493         /// your Message
494         private void ReportQueueAction(CaseCell yourTarget, string yourMessage)
495         {
496             if (OnQueueChangeEvent != null)
497             {
498                 OnQueueChangeEvent(yourTarget, yourMessage);
499             }
500         }
501 
502 
503         /// 
504         /// you must readyStart before get nextCase (and here also can reset the StartCase)
505         /// 
506         /// your StartCase
507         public void readyStart(CaseCell yourStartCase)
508         {
509             myCsaeQueueList.Clear();
510             AddCsaeQueue(new myCsaeQueue(yourStartCase));
511             ReportQueueAction(yourStartCase, "");
512         }
513 
514 
515         /// 
516         /// you must readyStart before get nextCase (and here also can reset the StartCase)
517         /// 
518         /// your StartCase
519         /// it will change the behaviour that is it will go through all case(now it is replaced by [goto])
520         public void readyStart(CaseCell yourStartCase, bool yourIsThrough)
521         {
522             readyStart(yourStartCase);
523             isThroughAllCase = yourIsThrough;
524         }
525 
526         /// 
527         /// i will get the next myTreeTagInfo in myCaseRunTime
528         /// 
529         /// the CaseCell you want
530         public CaseCell nextCase()
531         {
532             if (myCsaeQueueList.Count > 0)
533             {
534                 CaseCell tempTreeNodeCase = myCsaeQueueList[myCsaeQueueList.Count - 1].nextCase();
535                 if(tempTreeNodeCase==null)
536                 {
537                     DelCsaeQueue(myCsaeQueueList[myCsaeQueueList.Count - 1]);
538                     return nextCase();
539                 }
540                 else
541                 {
542                     return tempTreeNodeCase;
543                 }
544             }
545             else
546             {
547                 return null;
548             }
549         }
550 
551         /// 
552         /// here i will jump into other case in myCaseRunTime
553         /// 
554         /// your Project Id
555         /// your Case Id
556         /// is success
557         public bool gotoMyCase(int yourProjectId, int yourCaseId, Dictionary<int, Dictionary<int, CaseCell>> myRunTimeCaseDictionary)
558         {
559             if (myRunTimeCaseDictionary.ContainsKey(yourProjectId))
560             {
561                 if (myRunTimeCaseDictionary[yourProjectId].ContainsKey(yourCaseId))
562                 {
563                     AddCsaeQueue(new myCsaeQueue(myRunTimeCaseDictionary[yourProjectId][yourCaseId]), yourProjectId, yourCaseId);
564                     return true;
565                 }
566                 else
567                 {
568                     ReportQueueAction(myCsaeQueueList[myCsaeQueueList.Count - 1].NowCaseNode, "▼GoTo error");
569                     return false;
570                 }
571             }
572             else
573             {
574                 return false;
575             }
576         }
577     }
View Code

 

而最终myCaseRunTime也是为CaseActionActuator 服务的,现在来看下CaseActionActuator。

CaseActionActuator相对比较多一点,因为要完成的功能会多一些,跟其他模块的联系也会大一些

一个基于.NET平台的自动化/压力测试系统设计简述_第6张图片

 

这个可能看起来就很乱了,上图的模块主要就是一个Case文件的在系统中的表现,可以理解为一个User,这个User通过Case脚本文件可以执行一套业务,执行过程也是独立的,环境,线程,数据也都是独立的。所以可以创建任意多个这种模块以模拟大量的用户同时操作,当然脚本可以使用不同的脚本文件,也可以使用相同脚本文件(若使用相同脚本文件系统会对当前模块进行深度克隆,克隆的用户共享部分不会影响运行的数据)。该模块还可以选择以Cell对UI控件进行绑定,以达到执行过程中用户界面的友好反馈,当然不同的UI控件的动态效果需要单独的处理(处理由另一个辅助模块myActionActuator完成)

这个模块的图起来乱点,不过code相对清晰,有兴趣可以看下面代码(贴出的是关键部分)

   1 /// 
   2     /// CASE执行器
   3     /// 
   4     public class CaseActionActuator:IDisposable,ICloneable
   5     {
   6         #region Private Class
   7         /// 
   8         /// 描述执行可能所需要的附加信息(可扩展),可以为null
   9         /// 
  10         private class ExecutiveAdditionalInfo
  11         {
  12             private bool isRetry;
  13             private int tryTimes;
  14             private bool isStoping;
  15             private bool isTryCase;
  16 
  17             public ExecutiveAdditionalInfo(bool yourIstry,int yourTryTimes)
  18             {
  19                 isRetry = yourIstry;
  20                 tryTimes = yourTryTimes;
  21                 isStoping = false;
  22                 isTryCase = false;
  23             }
  24 
  25             public ExecutiveAdditionalInfo(bool yourStoping)
  26             {
  27                 isRetry = false;
  28                 isTryCase = false;
  29                 tryTimes = -98;
  30                 isStoping = yourStoping;
  31             }
  32 
  33             public ExecutiveAdditionalInfo(bool yourStoping, bool yourTryCase)
  34             {
  35                 isRetry = false;
  36                 isTryCase = yourTryCase;
  37                 tryTimes = -98;
  38                 isStoping = yourStoping;
  39             }
  40 
  41             public bool IsReTry
  42             {
  43                 get
  44                 {
  45                     return isRetry;
  46                 }
  47                 set
  48                 {
  49                     isRetry = value;
  50                 }
  51             }
  52 
  53             public bool IsTryCase
  54             {
  55                 get
  56                 {
  57                     return isTryCase;
  58                 }
  59             }
  60 
  61             public int TryTimes
  62             {
  63                 get
  64                 {
  65                     return tryTimes;
  66                 }
  67                 set
  68                 {
  69                     tryTimes = value;
  70                 }
  71             }
  72 
  73             public bool IsStoping
  74             {
  75                 get
  76                 {
  77                     return isStoping;
  78                 }
  79             }
  80         }
  81 
  82         /// 
  83         /// 描述单次执行所需的基本数据集
  84         /// 
  85         private class ExecutivebasicData
  86         {
  87             myRunCaseData runCaseData;
  88             TreeNode executiveNode;
  89 
  90             public ExecutivebasicData(myRunCaseData yourCaseData,TreeNode yourExecutiveNode)
  91             {
  92                 runCaseData = yourCaseData;
  93                 executiveNode = yourExecutiveNode;
  94             }
  95         }
  96 
  97         #endregion
  98 
  99         /// 
 100         /// 克隆Actuator的根
 101         /// 
 102         private CaseActionActuator rootActuator;
 103 
 104         /// 
 105         /// 执行线程同步器
 106         /// 
 107         private ManualResetEvent myManualResetEvent = new ManualResetEvent(true);
 108 
 109         /// 
 110         /// 执行器名称
 111         /// 
 112         private string myName;
 113 
 114         /// 
 115         /// Actuator State 
 116         /// 
 117         private CaseActuatorState runState;
 118 
 119 
 120         /// 
 121         /// case guide diver
 122         /// 
 123         private myCaseRunTime caseRunTime;
 124 
 125         /// 
 126         /// ExecutionDevice List with his name【执行驱动器映射表】
 127         /// 
 128         private Dictionary<string, ICaseExecutionDevice> myExecutionDeviceList;
 129 
 130         /// 
 131         /// Parameter List
 132         /// 
 133         private Dictionary<string, string> runActuatorParameterList;
 134 
 135         /// 
 136         /// StaticData List
 137         /// 
 138         private Dictionary<string, IRunTimeStaticData> runActuatorStaticDataList;
 139 
 140         /// 
 141         /// Execution Result List
 142         /// 
 143         private List runExecutionResultList;
 144 
 145         /// 
 146         /// RunTimeCaseDictionary
 147         /// 
 148         private Dictionary<int, Dictionary<int, CaseCell>> runTimeCaseDictionary;
 149 
 150         /// 
 151         /// ProjctCollection
 152         /// 
 153         private ProjctCollection runCellProjctCollection;
 154 
 155         /// 
 156         /// Actuator Task Thread
 157         /// 
 158         private Thread myActuatorTaskThread;
 159         private Thread myActuatorTryThread;
 160 
 161         /// 
 162         /// the thread not used and do not make it out of control
 163         /// 
 164         private List invalidThreadList;
 165 
 166         private string nowExecutiveData;
 167         private string myErrorInfo;
 168 
 169         private int executiveThinkTime;
 170         private int caseThinkTime;
 171 
 172         public delegate void delegateGetExecutiveDataEventHandler(string yourTitle, string yourContent);
 173         public delegate void delegateGetActionErrorEventHandler(string yourContent);
 174         public delegate void delegateGetExecutiveResultEventHandler(string sender, myExecutionDeviceResult yourResult);
 175         public delegate void delegateGetActuatorStateEventHandler(string sender, CaseActuatorState yourState);
 176         public delegate void delegateActuatorParameterListEventHandler();
 177 
 178 
 179         public event delegateGetExecutiveData OnGetExecutiveData;
 180         public event delegateGetExecutiveData OnGetActionError;
 181         public event delegateGetExecutiveResultEventHandler OnExecutiveResult;
 182         public event delegateGetActuatorStateEventHandler OnActuatorStateChanged;
 183         public delegateActuatorParameterListEventHandler OnActuatorParameterListChanged;  //外部需要访问 event修饰后,会禁止非创建类服务
 184 
 185 
 186         /// 
 187         /// 构造函数
 188         /// 
 189         public CaseActionActuator()
 190         {
 191             rootActuator = null;
 192             myExecutionDeviceList = new Dictionary<string, ICaseExecutionDevice>();
 193             runActuatorParameterList = new Dictionary<string, string>();
 194             runActuatorStaticDataList = new Dictionary<string, IRunTimeStaticData>();
 195             runExecutionResultList = new List();
 196             invalidThreadList = new List();
 197             myErrorInfo = "";
 198             myName = "Main Actuator";
 199             runState = CaseActuatorState.Stop;
 200             executiveThinkTime = 0;
 201         }
 202 
 203         /// 
 204         /// 构造函数
 205         /// 
 206         /// 当前执行器的名称
 207         public CaseActionActuator(string yourName)
 208         {
 209             rootActuator = null;
 210             myExecutionDeviceList = new Dictionary<string, ICaseExecutionDevice>();
 211             runActuatorParameterList = new Dictionary<string, string>();
 212             runActuatorStaticDataList = new Dictionary<string, IRunTimeStaticData>();
 213             runExecutionResultList = new List();
 214             invalidThreadList = new List();
 215             myErrorInfo = "";
 216             myName = yourName;
 217             runState = CaseActuatorState.Stop; ;
 218         }
 219 
 220         /// 
 221         /// 克隆
 222         /// 
 223         /// 克隆对象
 224         public object Clone()
 225         {
 226             CaseActionActuator cloneActuator = new CaseActionActuator();
 227             cloneActuator.rootActuator = null;
 228             cloneActuator.myExecutionDeviceList = myExecutionDeviceList.MyClone();
 229             cloneActuator.runActuatorParameterList = runActuatorParameterList.MyClone<string,string>();
 230             cloneActuator.runActuatorStaticDataList = runActuatorStaticDataList.MyClone();
 231             //cloneActuator.runExecutionResultList = new List();
 232             cloneActuator.SetCaseRunTime(this.runTimeCaseDictionary, this.runCellProjctCollection);
 233             cloneActuator.caseThinkTime = this.caseThinkTime;
 234             return cloneActuator;
 235         }
 236 
 237         
 238 
 239         /// 
 240         /// 获取或设置执行器标识名
 241         /// 
 242         public string MyName
 243         {
 244             get
 245             {
 246                 return myName;
 247             }
 248             set
 249             {
 250                 myName = value;
 251             }
 252         }
 253 
 254         /// 
 255         /// 获取或设置执行器的全局思考/等待时间
 256         /// 
 257         public int ExecutiveThinkTime
 258         {
 259             get
 260             {
 261                 return executiveThinkTime;
 262             }
 263             set
 264             {
 265                 executiveThinkTime = value;
 266             }
 267         }
 268 
 269         /// 
 270         /// 获取【CaseActionActuator】运行状态
 271         /// 
 272         public CaseActuatorState Runstate
 273         {
 274             get
 275             {
 276                 return runState;
 277             }
 278         }
 279 
 280         /// 
 281         /// 获取当前任务执行进度
 282         /// 
 283         public Listint ,int >> RunProgress
 284         {
 285             get
 286             {
 287                 if (caseRunTime != null)
 288                 {
 289                     return caseRunTime.GetNowCountProgress;
 290                 }
 291                 else
 292                 {
 293                     return null;
 294                 }
 295             }
 296         }
 297 
 298         /// 
 299         /// 获取ErrorInfo属性
 300         /// 
 301         public string ErrorInfo
 302         {
 303             get
 304             {
 305                 return myErrorInfo;
 306             }
 307         }
 308 
 309         /// 
 310         /// 获取执行过程
 311         /// 
 312         public string NowExecutiveData
 313         {
 314             get
 315             {
 316                 return nowExecutiveData;
 317 
 318             }
 319         }
 320 
 321         /// 
 322         /// 获取当前任务执行结果列表
 323         /// 
 324         public List NowExecutionResultList
 325         {
 326             get
 327             {
 328                 return runExecutionResultList;
 329             }
 330         }
 331 
 332         /// 
 333         /// 获取当前参数化数据列表
 334         /// 
 335         public Dictionary<string, string> NowParameterList
 336         {
 337             get
 338             {
 339                 return runActuatorParameterList;
 340             }
 341         }
 342 
 343         /// 
 344         /// 获取当前静态参数化数据列表
 345         /// 
 346         public Dictionary<string, IRunTimeStaticData> NowStaticDataList
 347         {
 348             get
 349             {
 350                 return runActuatorStaticDataList;
 351             }
 352         }
 353 
 354         /// 
 355         /// 获取当前执行器列表
 356         /// 
 357         public Dictionary<string, ICaseExecutionDevice> NowExecutionDeviceList
 358         {
 359             get
 360             {
 361                 return myExecutionDeviceList;
 362             }
 363         }
 364 
 365         /// 
 366         /// 获取当前CASE列表
 367         /// 
 368         public Dictionary<int, Dictionary<int, CaseCell>> RunTimeCaseDictionary
 369         {
 370             get
 371             {
 372                 return runTimeCaseDictionary;
 373             }
 374         }
 375 
 376         /// 
 377         /// 获取当前ProjctCollection
 378         /// 
 379         public ProjctCollection RunCellProjctCollection
 380         {
 381             get
 382             {
 383                 return runCellProjctCollection;
 384             }
 385         }
 386 
 387         /// 
 388         /// 获取当前执行器是否填充过数据
 389         /// 
 390         public bool IsActuatorDataFill
 391         {
 392             get
 393             {
 394                 return ((runCellProjctCollection != null) && (runCellProjctCollection != null));
 395             }
 396         }
 397 
 398         /// 
 399         /// i can updata you myRunTimeCaseDictionary()
 400         /// 
 401         /// you myRunTimeCaseDictionary
 402         public void UpdataRunTimeCaseDictionary(Dictionary<int, Dictionary<int, CaseCell>> yourCaseDictionary)
 403         {
 404             runTimeCaseDictionary = yourCaseDictionary;
 405         }
 406 
 407         //RunTime Queue队列变化时通知
 408         void caseRunTime_OnQueueChangeEvent(CaseCell yourTarget, string yourMessage)
 409         {
 410             if (yourMessage != "")
 411             {
 412                 if (yourMessage.StartsWith(""))
 413                 {
 414                     //附加任务起始节点
 415                     myActionActuator.SetCaseNodeExpand(yourTarget);
 416                 }
 417                 else if (yourMessage.StartsWith(""))
 418                 {
 419                     //主任务起始节点
 420                     while(yourTarget.CaseType!=CaseType.Case)
 421                     {
 422                         if(yourTarget.IsHasChild)
 423                         {
 424                             yourTarget=yourTarget.ChildCells[0];
 425                         }
 426                         else
 427                         {
 428                             break;
 429                         }
 430                     }
 431                     myActionActuator.SetCaseNodeExpand(yourTarget);
 432                 }
 433                 yourMessage = "" + yourMessage + "";
 434             }
 435 
 436             myActionActuator.SetCaseNodeLoopChange(yourTarget, yourMessage);
 437         }
 438 
 439         //RunTime Queue 中Loop变化时通知
 440         void caseRunTime_OnLoopChangeEvent(CaseCell yourTarget, string yourMessage)
 441         {
 442             if (yourMessage!="")
 443             {
 444                 myActionActuator.SetCaseNodeExpand(yourTarget);
 445                 myActionActuator.SetCaseNodeLoopRefresh(yourTarget);
 446                 yourMessage = "" + yourMessage + "";
 447             }
 448             myActionActuator.SetCaseNodeLoopChange(yourTarget, yourMessage);
 449         }
 450 
 451 
 452         /// 
 453         /// i will load your ActionActuator (if your have another rule file ,please override or add a new realize)
 454         /// 
 455         /// source Node
 456         public void LoadScriptRunTime(XmlNode sourceNode)
 457         {
 458             if (sourceNode != null)
 459             {
 460                 if (sourceNode.HasChildNodes)
 461                 {
 462                     foreach (XmlNode tempNode in sourceNode.ChildNodes)
 463                     {
 464                         switch (tempNode.Name)
 465                         {
 466                             #region RunTimeParameter
 467                             case "RunTimeParameter":
 468                                 if (tempNode.HasChildNodes)
 469                                 {
 470                                     foreach (XmlNode tempNodeChild in tempNode.ChildNodes)
 471                                     {
 472                                         if (tempNodeChild.Name == "NewParameter")
 473                                         {
 474                                             if (tempNodeChild.Attributes["name"] != null)
 475                                             {
 476                                                 AddRunActuatorParameter(tempNodeChild.Attributes["name"].Value, tempNodeChild.InnerText);
 477                                             }
 478                                             else
 479                                             {
 480                                                 SetNowActionError("can not find name in ScriptRunTime - RunTimeParameter");
 481                                             }
 482                                         }
 483                                         else
 484                                         {
 485                                             SetNowActionError("find unkonw data in ScriptRunTime - RunTimeParameter");
 486                                         }
 487                                     }
 488                                 }
 489                                 break;
 490                             #endregion
 491 
 492                             #region RunTimeActuator
 493                             case "RunTimeActuator":
 494                                 if (tempNode.HasChildNodes)
 495                                 {
 496                                     string tempActuatorName = "";
 497                                     CaseProtocol tempActuatorProtocol = CaseProtocol.unknownProtocol;
 498                                     foreach (XmlNode tempNodeChild in tempNode.ChildNodes)
 499                                     {
 500                                         if (tempNodeChild.Name == "NewActuator")
 501                                         {
 502                                             if (tempNodeChild.Attributes["name"] != null && tempNodeChild.Attributes["protocol"] != null)
 503                                             {
 504                                                 tempActuatorName = tempNodeChild.Attributes["name"].Value;
 505                                                 try
 506                                                 {
 507                                                     tempActuatorProtocol = (CaseProtocol)Enum.Parse(typeof(CaseProtocol), tempNodeChild.Attributes["protocol"].Value);
 508                                                 }
 509                                                 catch
 510                                                 {
 511                                                     tempActuatorProtocol = CaseProtocol.unknownProtocol;
 512                                                     SetNowActionError("find unknown Protocol in ScriptRunTime - RunTimeActuator");
 513                                                 }
 514                                                 switch (tempActuatorProtocol)
 515                                                 {
 516                                                     case CaseProtocol.vanelife_http:
 517                                                         myConnectForVanelife_http ConnectInfo = new myConnectForVanelife_http(tempActuatorProtocol, CaseTool.getXmlInnerVaule(tempNodeChild, "dev_key"), CaseTool.getXmlInnerVaule(tempNodeChild, "dev_secret"), CaseTool.getXmlInnerVaule(tempNodeChild, "default_url"));
 518                                                         AddExecutionDevice(tempActuatorName, ConnectInfo);
 519                                                         break;
 520                                                     case CaseProtocol.http:
 521                                                         myConnectForHttp ConnectInfo_http = new myConnectForHttp(tempActuatorProtocol, CaseTool.getXmlInnerVaule(tempNodeChild, "default_url"));
 522                                                         AddExecutionDevice(tempActuatorName, ConnectInfo_http);
 523                                                         break;
 524                                                     default:
 525                                                         SetNowActionError("find nonsupport Protocol in ScriptRunTime ");
 526                                                         break;
 527                                                 }
 528                                             }
 529                                             else
 530                                             {
 531                                                 SetNowActionError("can not find name or protocol in ScriptRunTime - RunTimeActuator");
 532                                             }
 533                                         }
 534                                         else
 535                                         {
 536                                             SetNowActionError("find unkonw data in ScriptRunTime - RunTimeActuator");
 537                                         }
 538                                     }
 539                                 }
 540                                 break;
 541                             #endregion
 542 
 543                             #region RunTimeStaticData
 544                             case "RunTimeStaticData":
 545                                 if (tempNode.HasChildNodes)
 546                                 {
 547                                     foreach (XmlNode tempNodeChild in tempNode.ChildNodes)
 548                                     {
 549                                         if (tempNodeChild.Name == "NewStaticData")
 550                                         {
 551                                             if (tempNodeChild.Attributes["name"] != null && tempNodeChild.Attributes["type"] != null)
 552                                             {
 553                                                 CaseStaticDataType tempType;
 554                                                 string tempName = tempNodeChild.Attributes["name"].Value;
 555                                                 string tempTypeStr = tempNodeChild.Attributes["type"].Value;
 556                                                 string tempVaule = tempNodeChild.InnerText;
 557                                                 try
 558                                                 {
 559                                                     tempType = (CaseStaticDataType)Enum.Parse(typeof(CaseStaticDataType), "staticData_"+tempTypeStr);
 560                                                 }
 561                                                 catch
 562                                                 {
 563                                                     SetNowActionError("find unknown type in RunTimeStaticData - ScriptRunTime");
 564                                                     continue;
 565                                                 }
 566                                                 switch (tempType)
 567                                                 {
 568                                                     case CaseStaticDataType.staticData_index:
 569                                                         myStaticDataIndex tempStaticDataIndex;
 570                                                         string tempTypeError;
 571                                                         if (myCaseDataTypeEngine.getIndexStaticData(out tempStaticDataIndex, out tempTypeError, tempVaule))
 572                                                         {
 573                                                             runActuatorStaticDataList.myAdd(tempName, tempStaticDataIndex);
 574                                                         }
 575                                                         else
 576                                                         {
 577                                                             runActuatorStaticDataList.myAdd(tempName, tempStaticDataIndex);
 578                                                             SetNowActionError(tempVaule);
 579                                                         }
 580                                                         break;
 581                                                     case CaseStaticDataType.staticData_random:                                              
 582                                                         myStaticDataRandomStr tempStaticDataRandomStr;
 583                                                         if(myCaseDataTypeEngine.getRandomStaticData(out tempStaticDataRandomStr,out tempTypeError,tempVaule))
 584                                                         {
 585                                                             runActuatorStaticDataList.myAdd(tempName, tempStaticDataRandomStr);
 586                                                         }
 587                                                         else
 588                                                         {
 589                                                             runActuatorStaticDataList.myAdd(tempName, tempStaticDataRandomStr);
 590                                                             SetNowActionError(tempVaule);
 591                                                         }
 592                                                         break;
 593                                                     case CaseStaticDataType.staticData_time:
 594                                                         myStaticDataNowTime tempStaticDataNowTime;
 595                                                         myCaseDataTypeEngine.getTimeStaticData(out tempStaticDataNowTime, tempVaule);
 596                                                         runActuatorStaticDataList.myAdd(tempName, tempStaticDataNowTime);
 597                                                         break;
 598                                                     default:
 599                                                         SetNowActionError("find nonsupport Protocol in RunTimeStaticData - ScriptRunTime ");
 600                                                         break;
 601                                                 }
 602 
 603                                             }
 604                                             else
 605                                             {
 606                                                 SetNowActionError("can not find name or type in RunTimeStaticData - ScriptRunTime");
 607                                             }
 608                                         }
 609                                         else
 610                                         {
 611                                             SetNowActionError("find unkonw data in RunTimeStaticData - ScriptRunTime");
 612                                         }
 613                                     }
 614                                 }
 615                                 break;
 616                             #endregion
 617                             
 618                             default:
 619                                 SetNowActionError("find unkonw data in ScriptRunTime");
 620                                 break;
 621                         }
 622                     }
 623                 }
 624                 else
 625                 {
 626                     SetNowActionError("Error Source Node");
 627                 }
 628             }
 629         }
 630 
 631         /// 
 632         /// 连接这些器
 633         /// 
 634         public void ConnectExecutionDevice()
 635         {
 636             SetNowExecutiveData("CaseExecutionDevice connecting ......");
 637             foreach (KeyValuePair<string, ICaseExecutionDevice> tempKvp in myExecutionDeviceList)
 638             {
 639                 if (tempKvp.Value.executionDeviceConnect())
 640                 {
 641                     SetNowExecutiveData(string.Format("【RunTimeActuator】:{0} 连接成功", tempKvp.Key));
 642                 }
 643                 else
 644                 {
 645                     SetNowActionError(tempKvp.Key + "connect fail");
 646                 }
 647             }
 648             SetNowExecutiveData("Connect complete");
 649         }
 650 
 651         /// 
 652         /// 为执行器断开连接
 653         /// 
 654         public void DisconnectExecutionDevice()
 655         {
 656             foreach (KeyValuePair<string, ICaseExecutionDevice> tempKvp in myExecutionDeviceList)
 657             {
 658                 tempKvp.Value.executionDeviceClose();
 659             }
 660         }
 661 
 662         /// 
 663         /// 创建任务
 664         /// 
 665         private void  CreateNewActuatorTask()
 666         {
 667             //Thread myThreadTest = new Thread(new ThreadStart(ExecutiveActuatorTask),10240);
 668             if (myActuatorTaskThread!=null)
 669             {
 670                 if(myActuatorTaskThread.IsAlive)
 671                 {
 672                     invalidThreadList.Add(myActuatorTaskThread);
 673                     ClearInvalidThreadList();
 674                     SetNowActionError("Forced to terminate the residual task");
 675                 }
 676             }
 677             myActuatorTaskThread = new Thread(new ThreadStart(ExecutiveActuatorTask));
 678             myActuatorTaskThread.Name = myName + "_ExecutiveActuatorTask";
 679             myActuatorTaskThread.Priority = ThreadPriority.Normal;
 680             myActuatorTaskThread.IsBackground = true;
 681             myActuatorTaskThread.Start();
 682         }
 683 
 684         /// 
 685         /// 执行任务
 686         /// 
 687         private void ExecutiveActuatorTask()
 688         {
 689             ConnectExecutionDevice();
 690             CaseCell nowExecutiveNode = null;
 691             myRunCaseData nowRunCaseData = null;
 692             ExecutiveAdditionalInfo nowAdditionalInfo;
 693 
 694             while((nowExecutiveNode=caseRunTime.nextCase())!=null)
 695             {
 696                 if ((nowRunCaseData = nowExecutiveNode.CaseRunData) != null)
 697                 {
 698                     nowAdditionalInfo = null;
 699                     ExecutiveAnCases(nowRunCaseData, nowExecutiveNode,ref nowAdditionalInfo);
 700 
 701                     while (nowAdditionalInfo != null)
 702                     {
 703                         //Stoping
 704                         if (nowAdditionalInfo.IsStoping)
 705                         {
 706                             SetNowExecutiveData("操作者主动终止任务");
 707                             goto EndTask;
 708                         }
 709                         //ReTry
 710                         if(nowAdditionalInfo.IsReTry)
 711                         {
 712                             nowAdditionalInfo.IsReTry = false;
 713                             ExecutiveAnCases(nowRunCaseData, nowExecutiveNode,ref nowAdditionalInfo);
 714                         }
 715                         else
 716                         {
 717                             break;
 718                         }
 719                     }
 720                 }
 721                 else
 722                 {
 723                     //没有执行数据请处理
 724                     SetNowActionError("严重异常,未找到合法执行数据");
 725 
 726                 }
 727             }
 728             EndTask:
 729             DisconnectExecutionDevice();
 730             SetRunState(CaseActuatorState.Stop);
 731             SetNowExecutiveData("任务已结束");
 732         }
 733 
 734         /// 
 735         /// 创建一个定项执行任务
 736         /// 
 737         /// 
 738         private void CreateNewActuatorTry(CaseCell yourTryNode)
 739         {
 740             if (myActuatorTryThread != null)
 741             {
 742                 if (myActuatorTryThread.IsAlive)
 743                 {
 744                     invalidThreadList.Add(myActuatorTryThread);
 745                     ClearInvalidThreadList();
 746                     SetNowActionError("Forced to terminate the residual task");
 747                 }
 748             }
 749             myActuatorTryThread = new Thread(new ParameterizedThreadStart(ExecutiveActuatorTry));
 750             myActuatorTryThread.Name = myName + "_ExecutiveActuatorTry";
 751             myActuatorTryThread.Priority = ThreadPriority.Normal;
 752             myActuatorTryThread.IsBackground = true;
 753             myActuatorTryThread.Start(yourTryNode);
 754         }
 755 
 756         /// 
 757         /// 执行一次定项测试
 758         /// 
 759         private void ExecutiveActuatorTry(object yourTryNode)
 760         {
 761             ConnectExecutionDevice();
 762             CaseCell nowExecutiveNode = (CaseCell)yourTryNode;
 763             myRunCaseData nowRunCaseData = nowExecutiveNode.CaseRunData;
 764             ExecutiveAdditionalInfo nowAdditionalInfo;
 765 
 766             if (nowRunCaseData != null)
 767             {
 768                 nowAdditionalInfo = new ExecutiveAdditionalInfo(false, true);
 769                 ExecutiveAnCases(nowRunCaseData, nowExecutiveNode, ref nowAdditionalInfo);
 770             }
 771             else
 772             {
 773                 //没有执行数据请处理
 774                 SetNowActionError("严重异常,未找到合法执行数据");
 775             }
 776 
 777             DisconnectExecutionDevice();
 778             SetRunState(CaseActuatorState.Stop);
 779             SetNowExecutiveData("定项执行完成");
 780         }
 781 
 782         /// 
 783         /// 执行指定的Case
 784         /// 
 785         /// myRunCaseData
 786         /// now CaseCell
 787         private void ExecutiveAnCases(myRunCaseData nowRunCaseData, CaseCell nowExecutiveNode, ref ExecutiveAdditionalInfo nowAdditionalInfo)
 788         {
 789             bool tempIsBreakError = false;
 790             myExecutionDeviceResult executionResult;
 791 
 792             if(runState==CaseActuatorState.Pause)
 793             {
 794                 myActionActuator.SetCaseNodePause(nowExecutiveNode);
 795             }
 796             myManualResetEvent.WaitOne();
 797             if (runState == CaseActuatorState.Stoping)
 798             {
 799                 nowAdditionalInfo = new ExecutiveAdditionalInfo(true);
 800                 myActionActuator.SetCaseNodeStop(nowExecutiveNode);
 801                 return;
 802             }
 803 
 804             if (nowRunCaseData.errorMessages == null)
 805             {
 806                 if (myExecutionDeviceList.ContainsKey(nowRunCaseData.testContent.myCaseActuator))
 807                 {
 808                     var nowDevice = myExecutionDeviceList[nowRunCaseData.testContent.myCaseActuator];
 809                 ExecutionDeviceRunLink:
 810                     if (nowDevice.isDeviceConnect)
 811                     {
 812                         //nowDevice.executionDeviceRun()
 813                         myActionActuator.SetCaseNodeRunning(nowExecutiveNode);
 814                         executionResult = nowDevice.executionDeviceRun(nowRunCaseData.testContent, OnGetExecutiveData, myName,runActuatorParameterList, runActuatorStaticDataList, nowRunCaseData.id);
 815                         HandleCaseExecutiveResul(nowRunCaseData, nowExecutiveNode, executionResult,ref nowAdditionalInfo);
 816 
 817                     }
 818                     else
 819                     {
 820                         //Device没有连接
 821                         SetNowExecutiveData(string.Format("【ID:{0}】 {1}连接中断,尝试连接中···", nowRunCaseData.id, nowRunCaseData.testContent.myCaseActuator));
 822                         if (nowDevice.executionDeviceConnect())
 823                         {
 824                             //nowDevice.executionDeviceRun()
 825                             goto ExecutionDeviceRunLink;
 826                         }
 827                         else
 828                         {
 829                             SetNowExecutiveData(string.Format("【ID:{0}】 {1}连接失败", nowRunCaseData.id, nowRunCaseData.testContent.myCaseActuator));
 830                             myActionActuator.SetCaseNodeConnectInterrupt(nowExecutiveNode);
 831 
 832                             tempIsBreakError = true;
 833                             executionResult = new myExecutionDeviceResult(nowRunCaseData.id, "CaseActuator连接失败");
 834                         }
 835                     }
 836                 }
 837                 else
 838                 {
 839                     //testContent没有找到合适的myCaseActuator
 840                     SetNowExecutiveData(string.Format("【ID:{0}】 未找到指定CaseActuator", nowRunCaseData.id));
 841                     myActionActuator.SetCaseNodeNoActuator(nowExecutiveNode);
 842                     myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 843 
 844                     tempIsBreakError = true;
 845                     executionResult = new myExecutionDeviceResult(nowRunCaseData.id, "未找到指定CaseActuator");
 846                 }
 847             }
 848             else
 849             {
 850                 //nowRunCaseData有错误
 851                 SetNowActionError(string.Format("【ID:{0}】 执行数据脚本存在错误", nowRunCaseData.id));
 852                 myActionActuator.SetCaseNodeAbnormal(nowExecutiveNode);
 853 
 854                 tempIsBreakError = true;
 855                 executionResult = new myExecutionDeviceResult(nowRunCaseData.id, "执行数据脚本存在错误" + nowRunCaseData.errorMessages);
 856             }
 857 
 858             //AddExecutionResult
 859             AddExecutionResult(executionResult);
 860 
 861             //Sleep
 862             if (!tempIsBreakError)
 863             {
 864                 int tempSleepTime = executiveThinkTime + caseThinkTime;
 865                 if(tempSleepTime>0)
 866                 {
 867                     SetNowExecutiveData(string.Format("sleep {0} ms···", tempSleepTime));
 868                     Thread.Sleep(tempSleepTime);
 869                 }
 870             }
 871 
 872             //nowExecutiveNode.TreeView.Invoke(new delegateBasicAnonymous(() => { }));
 873             //nowExecutiveNode.TreeView.Invoke(new delegateBasicAnonymous(() => nowExecutiveNode.BackColor = System.Drawing.Color.LightSkyBlue));  
 874            
 875         }
 876 
 877 
 878         /// 
 879         /// 处理断言,及结果封装.用于【ExecutiveActuatorTask】
 880         /// 
 881         /// 确保其不为null
 882         /// 确保其不为null
 883         /// 
 884         private void HandleCaseExecutiveResul(myRunCaseData yourRunData, CaseCell nowExecutiveNode, myExecutionDeviceResult yourExecutionResult, ref ExecutiveAdditionalInfo nowAdditionalInfo)
 885         {
 886             string tempError;
 887             yourExecutionResult.caseId = yourRunData.id;
 888             if (yourExecutionResult.additionalEroor != null)
 889             {
 890                 myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 891             }
 892             yourExecutionResult.expectMethod = yourRunData.caseExpectInfo.myExpectType;
 893             yourExecutionResult.expectContent = yourRunData.caseExpectInfo.myExpectContent.getTargetContentData(runActuatorParameterList, runActuatorStaticDataList, out tempError);
 894             if (tempError != null)
 895             {
 896                 myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 897                 yourExecutionResult.additionalEroor = yourExecutionResult.additionalEroor.myAddValue(tempError);
 898             }
 899             if (CaseTool.CheckBackData(yourExecutionResult.backContent, yourExecutionResult.expectContent, yourRunData.caseExpectInfo.myExpectType))
 900             {
 901                 yourExecutionResult.result = CaseResult.Pass;
 902                 myActionActuator.SetCaseNodePass(nowExecutiveNode);
 903             }
 904             else
 905             {
 906                 yourExecutionResult.result = CaseResult.Fail;
 907                 myActionActuator.SetCaseNodeFial(nowExecutiveNode);
 908             }
 909 
 910             #region ParameterSaves
 911             if(yourRunData.caseAttribute.myParameterSaves!=null)
 912             {
 913                 foreach (ParameterSave tempParameterSave in yourRunData.caseAttribute.myParameterSaves)
 914                 {
 915                     string tempPickVaule = null;
 916                     switch (tempParameterSave.parameterFunction)
 917                     {
 918                         case PickOutFunction.pick_json:
 919                             tempPickVaule = CaseTool.PickJsonParameter(tempParameterSave.parameterFindVaule, yourExecutionResult.backContent);
 920                             break;
 921                         case PickOutFunction.pick_str:
 922                             string tempFindVaule;
 923                             int tempLen;
 924                             CaseTool.GetStrPickData(tempParameterSave.parameterFindVaule,out tempFindVaule,out tempLen);
 925                             if (tempFindVaule!=null)
 926                             {
 927                                 tempPickVaule = CaseTool.PickStrParameter(tempFindVaule, tempLen , yourExecutionResult.backContent);
 928                             }
 929                             else
 930                             {
 931                                 tempError = string.Format("【ID:{0}】ParameterSave 脚本数据不合法", yourRunData.id);
 932                                 yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
 933                                 SetNowActionError(tempError);
 934                                 myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 935                             }
 936                             
 937                             break;
 938                         case PickOutFunction.pick_xml:
 939                             tempPickVaule = CaseTool.PickXmlParameter(tempParameterSave.parameterFindVaule, yourExecutionResult.backContent);
 940                             break;
 941                         default:
 942                             tempError = string.Format("【ID:{0}】 ParameterSave 暂不支持该数据提取方式", yourRunData.id);
 943                             yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
 944                             SetNowActionError(tempError);
 945                             myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 946                             break;
 947                     }
 948                     if(tempPickVaule!=null)
 949                     {
 950                         SetNowActionError(string.Format("【ID:{0}】 ParameterSave 在执行结果中未找到指定参数", yourRunData.id));
 951                     }
 952                     else
 953                     {
 954                         AddRunActuatorParameter(tempParameterSave.parameterName, tempPickVaule);
 955                     }
 956                 }
 957             }
 958             #endregion
 959 
 960             #region actions
 961             if (yourRunData.actions != null)
 962             {
 963                 if (yourRunData.actions.Keys.Contains(yourExecutionResult.result))
 964                 {
 965                     switch (yourRunData.actions[yourExecutionResult.result].caseAction)
 966                     {
 967                         case CaseAction.action_alarm:
 968                             if (yourRunData.actions[yourExecutionResult.result].addInfo != null)
 969                             {
 970                                 VoiceService.Speak(yourRunData.actions[yourExecutionResult.result].addInfo);
 971                                 SetNowExecutiveData("【action_alarm】");
 972                             }
 973                             else
 974                             {
 975                                 VoiceService.Beep();
 976                             }
 977                             break;
 978                         case CaseAction.action_continue:
 979                             //do nothing
 980                             break;
 981                         case CaseAction.action_goto:
 982                             if (nowAdditionalInfo != null)
 983                             {
 984                                 //定项不执行goto
 985                                 if(nowAdditionalInfo.IsTryCase)
 986                                 {
 987                                     break;
 988                                 }
 989                             }
 990                             if (yourRunData.actions[yourExecutionResult.result].addInfo == null)
 991                             {
 992                                 tempError = string.Format("【ID:{0}】 CaseAction Case数据中部没有发现目的ID", yourRunData.id);
 993                                 yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
 994                                 SetNowActionError(tempError);
 995                                 myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
 996                             }
 997                             else
 998                             {
 999                                 int tempCaseID;
1000                                 int tempProjectID;
1001                                 if (CaseTool.getTargetCaseID(yourRunData.actions[yourExecutionResult.result].addInfo, out tempProjectID, out tempCaseID))
1002                                 {
1003                                     if (caseRunTime.gotoMyCase(tempProjectID, tempCaseID, runTimeCaseDictionary ))
1004                                     {
1005                                         SetNowExecutiveData("【action_goto】");
1006                                         yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(string.Format("【action_goto】触发,已经跳转到Project:{0}  Case:{1}", tempProjectID, tempCaseID));
1007                                     }
1008                                     else
1009                                     {
1010                                         tempError = string.Format("【ID:{0}】action_goto跳转任务未成功", yourRunData.id);
1011                                         yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
1012                                         SetNowActionError(tempError);
1013                                     }
1014                                 }
1015                                 else
1016                                 {
1017                                     tempError = string.Format("【ID:{0}】 CaseAction 目标跳转Case不合法", yourRunData.id);
1018                                     yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
1019                                     SetNowActionError(tempError);
1020                                     myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
1021                                 }
1022                             }
1023                             break;
1024                         case CaseAction.action_retry:
1025                             if (nowAdditionalInfo != null)
1026                             {
1027                                 //定项不执行goto
1028                                 if (nowAdditionalInfo.IsTryCase)
1029                                 {
1030                                     break;
1031                                 }
1032                             }
1033                             if (yourRunData.actions[yourExecutionResult.result].addInfo != null)
1034                             {
1035                                 try
1036                                 {
1037                                     int tempTryTimes = int.Parse(yourRunData.actions[yourExecutionResult.result].addInfo);
1038                                     if (tempTryTimes > 0)
1039                                     {
1040                                         if (nowAdditionalInfo == null)
1041                                         {
1042                                             nowAdditionalInfo = new ExecutiveAdditionalInfo(true, tempTryTimes);
1043                                             if (nowAdditionalInfo.TryTimes > 0)
1044                                             {
1045                                                 SetNowExecutiveData("【action_retry】将被触发");
1046                                             }
1047                                             else
1048                                             {
1049                                                 nowAdditionalInfo.IsReTry = false;
1050                                             }
1051                                         }
1052                                         else
1053                                         {
1054                                             nowAdditionalInfo.TryTimes--;
1055                                             yourExecutionResult.additionalRemark += string.Format("retry: {0}/{1}", tempTryTimes, tempTryTimes - nowAdditionalInfo.TryTimes);
1056                                             if(  nowAdditionalInfo.TryTimes > 0)
1057                                             {
1058                                                 nowAdditionalInfo.IsReTry = true;
1059                                             }
1060                                         }
1061                                     }
1062 
1063                                 }
1064                                 catch
1065                                 {
1066                                     tempError = string.Format("【ID:{0}】 retry 解析错误", yourRunData.id);
1067                                     yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
1068                                     SetNowActionError(tempError);
1069                                     myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
1070                                 }
1071                             }
1072                             else
1073                             {
1074                                 if (nowAdditionalInfo == null)
1075                                 {
1076                                     nowAdditionalInfo = new ExecutiveAdditionalInfo(true, -99);
1077                                 }
1078                                 else
1079                                 {
1080                                     yourExecutionResult.additionalRemark += "【action_retry】 always";
1081                                     nowAdditionalInfo.IsReTry = true;
1082                                 }
1083                             }
1084                             break;
1085                         case CaseAction.action_stop:
1086                             PauseCaseScript();
1087                             break;
1088                         case CaseAction.action_unknow:
1089                             tempError = string.Format("【ID:{0}】 CaseAction 未能解析", yourRunData.id);
1090                             yourExecutionResult.additionalRemark = yourExecutionResult.additionalRemark.myAddValue(tempError);
1091                             SetNowActionError(tempError);
1092                             myActionActuator.SetCaseNodeContentWarning(nowExecutiveNode);
1093                             break;
1094                         default:
1095                             //do nothing
1096                             break;
1097 
1098                     }
1099                 }
1100             }
1101             #endregion
1102 
1103             #region Sleep
1104             if(yourRunData.caseAttribute.attributeDelay>0)
1105             {
1106                 caseThinkTime = yourRunData.caseAttribute.attributeDelay;
1107             }
1108             else
1109             {
1110                 if(caseThinkTime!=0)
1111                 {
1112                     caseThinkTime = 0;
1113                 }
1114             }
1115             #endregion
1116            
1117         }
1118 
1119         /// 
1120         /// 重置ErrorInfo
1121         /// 
1122         public void ResetErrorInfo()
1123         {
1124             myErrorInfo = "";
1125         }
1126 
1127         /// 
1128         /// 重置NowExecutiveData
1129         /// 
1130         public void ResetNowExecutiveData()
1131         {
1132             nowExecutiveData = "";
1133         }
1134 
1135         /// 
1136         /// 触发【OnGetExecutiveData】
1137         /// 
1138         /// 
1139         private void SetNowExecutiveData(string yourContent)
1140         {
1141             if (OnGetExecutiveData != null)
1142             {
1143                 this.OnGetExecutiveData(myName, yourContent);
1144             }
1145         }
1146 
1147         /// 
1148         /// 设置nowExecutiveData 及触发【OnGetExecutiveData】
1149         /// 
1150         /// 
1151         private void SetAndSaveNowExecutiveData(string yourContent)
1152         {
1153             nowExecutiveData = yourContent;
1154             if (OnGetExecutiveData != null)
1155             {
1156                 this.OnGetExecutiveData(myName, yourContent);
1157             }
1158         }
1159 
1160         /// 
1161         /// 触发【OnGetActionError】
1162         /// 
1163         /// Action Error Content
1164         private void SetNowActionError(string yourContent)
1165         {
1166             if (OnGetActionError != null)
1167             {
1168                 this.OnGetActionError(myName, yourContent);
1169             }
1170         }
1171 
1172         /// 
1173         ///  设置 myErrorInfo 并 触发【OnGetActionError】(若不想触发OnGetActionError请直接操作myErrorInfo)
1174         /// 
1175         /// Action Error Content
1176         private void SetAndSaveNowActionError(string yourContent)
1177         {
1178             myErrorInfo = yourContent;
1179             if (OnGetActionError != null)
1180             {
1181                 this.OnGetActionError(myName, myErrorInfo);
1182             }
1183         }
1184 
1185         /// 
1186         /// 设置 runState 并 触发【OnActuatorStateChanged】
1187         /// 
1188         /// 
1189         private void SetRunState(CaseActuatorState yourStae)
1190         {
1191             runState = yourStae;
1192             if(OnActuatorStateChanged!=null)
1193             {
1194                 this.OnActuatorStateChanged(myName, yourStae);
1195             }
1196         }
1197 
1198         /// 
1199         /// 添加执行结果到结果集并触发【OnExecutiveResult】
1200         /// 
1201         /// your ExecutionResult
1202         private void AddExecutionResult(myExecutionDeviceResult yourExecutionResult)
1203         {
1204             runExecutionResultList.Add(yourExecutionResult);
1205             if (OnExecutiveResult != null)
1206             {
1207                 this.OnExecutiveResult(myName, yourExecutionResult);
1208             }
1209         }
1210 
1211         /// 
1212         /// 添加ExecutionDevice
1213         /// 
1214         /// 
1215         /// 
1216         private bool AddExecutionDevice(string yourDeviceName, IConnectExecutiveData yourDeviceConnectInfo)
1217         {
1218             switch (yourDeviceConnectInfo.myCaseProtocol)
1219             {
1220                 case CaseProtocol.vanelife_http:
1221                     myExecutionDeviceList.myAdd(yourDeviceName, new CaseProtocolExecutionForVanelife_http((myConnectForVanelife_http)yourDeviceConnectInfo));
1222                     break;
1223                 case CaseProtocol.http:
1224                      myExecutionDeviceList.myAdd(yourDeviceName, new CaseProtocolExecutionForHttp((myConnectForHttp)yourDeviceConnectInfo));
1225                     break;
1226                 default:
1227                     SetNowActionError(yourDeviceName + " is an nonsupport Protocol");
1228                     break;
1229             }
1230             return true;
1231         }
1232 
1233         /// 
1234         /// 添加或修改【runActuatorParameterList】
1235         /// 
1236         ///  Parameter Name
1237         /// Parameter Vaule
1238         public void AddRunActuatorParameter(string yourParameterName, string yourParameterVaule)
1239         {
1240             runActuatorParameterList.myAdd(yourParameterName, yourParameterVaule);
1241             if (OnActuatorParameterListChanged!=null)
1242             {
1243                 this.OnActuatorParameterListChanged();
1244             }
1245         }
1246 
1247         /// 
1248         /// 设置 【case guide diver】
1249         /// 
1250         /// your Case ID list
1251         public void SetCaseRunTime(Dictionary<int, Dictionary<int, CaseCell>> yourCaseDictionary, ProjctCollection yourProjctCollection)
1252         {
1253             if (yourCaseDictionary != null && yourProjctCollection!=null)
1254             {
1255                 runTimeCaseDictionary = yourCaseDictionary;
1256                 runCellProjctCollection = yourProjctCollection;
1257                 caseRunTime = new myCaseRunTime();
1258                 caseRunTime.OnLoopChangeEvent += caseRunTime_OnLoopChangeEvent;
1259                 caseRunTime.OnQueueChangeEvent += caseRunTime_OnQueueChangeEvent;
1260             }
1261             else
1262             {
1263                 SetNowActionError("your CaseDictionary or ProjctCollection is null");
1264             }
1265         }
1266 
1267         /// 
1268         /// 获取执行器是否可以执行
1269         /// 
1270         /// is ok
1271         private bool IsActionActuatorCanRun(CaseCell yourStartNode)
1272         {
1273             if (runCellProjctCollection == null)
1274             {
1275                 SetAndSaveNowActionError("your CellProjctCollection is null");
1276                 return false;
1277             }
1278             if (runTimeCaseDictionary==null)
1279             {
1280                 SetAndSaveNowActionError("your RunTimeCaseDictionary is null");
1281                 return false;
1282             }
1283             if (caseRunTime == null)
1284             {
1285                 SetAndSaveNowActionError("your CaseRuntime is null");
1286                 return false;
1287             }
1288             if (myExecutionDeviceList.Count == 0)
1289             {
1290                 SetAndSaveNowActionError("can not find any ExecutionDevice");
1291                 return false;
1292             }
1293             if (yourStartNode==null)
1294             {
1295                 SetAndSaveNowActionError("your StartNode is null");
1296                 return false;
1297             }
1298             return true;
1299         }
1300 
1301         /// 
1302         /// 执行项目任务
1303         /// 
1304         /// 起始节点
1305         /// Success
1306         public bool RunCaseScript(CaseCell yourStartNode)
1307         {
1308             switch (runState)
1309             {
1310                 case CaseActuatorState.Running:
1311                     SetAndSaveNowActionError("当前任务还未结束");
1312                     return false;
1313                 case CaseActuatorState.Stoping:
1314                     SetAndSaveNowActionError("当前任务正在终止中");
1315                     return false;
1316                 case  CaseActuatorState.Pause:
1317                     SetRunState(CaseActuatorState.Running);
1318                     myManualResetEvent.Set();
1319                     SetNowExecutiveData("任务恢复");
1320                     return true;
1321                 case CaseActuatorState.Stop:
1322                     if (yourStartNode == null)
1323                     {
1324                         SetAndSaveNowActionError("未发现任何可用节点");
1325                         return false;
1326                     }
1327                     else if (!IsActionActuatorCanRun(yourStartNode))
1328                     {
1329                         return false;
1330                     }
1331                     caseRunTime.readyStart(yourStartNode);
1332                     runExecutionResultList.Clear();
1333                     SetRunState(CaseActuatorState.Running);
1334                     myManualResetEvent.Set();
1335                     CreateNewActuatorTask();
1336                     SetNowExecutiveData("任务开始");
1337                     return true;
1338                 case CaseActuatorState.Trying:
1339                     SetAndSaveNowActionError("存在未还未结束指定项任务");
1340                     return false;
1341                 default:
1342                     return false;
1343             }
1344             
1345         }
1346 
1347         /// 
1348         /// 暂停当前项目任务(可恢复)
1349         /// 
1350         /// Success
1351         public bool PauseCaseScript()
1352         {
1353             if (runState == CaseActuatorState.Running)
1354             {
1355                 myManualResetEvent.Reset();
1356                 SetRunState(CaseActuatorState.Pause);
1357                 SetNowExecutiveData("任务已暂停");
1358                 return true;
1359             }
1360             else
1361             {
1362                 SetAndSaveNowActionError("未发现处于运行状态中的任务");
1363                 return false;
1364             }
1365         }
1366 
1367         /// 
1368         /// 停止项目(不可恢复)
1369         /// 
1370         /// 
1371         public bool StopCaseScript()
1372         {
1373             if (runState == CaseActuatorState.Running)
1374             {
1375                 SetRunState(CaseActuatorState.Stoping);
1376                 SetNowExecutiveData("正在终止任务");
1377                 return true;
1378             }
1379             else if (runState == CaseActuatorState.Pause)
1380             {
1381                 myManualResetEvent.Set();
1382                 SetRunState(CaseActuatorState.Stoping);
1383                 SetNowExecutiveData("正在终止任务");
1384                 return true;
1385             }
1386             else if (runState == CaseActuatorState.Stoping)
1387             {
1388                 SetAndSaveNowActionError("正在终止任务");
1389                 return false;
1390             }
1391             else
1392             { 
1393                 SetAndSaveNowActionError("当前项目已经停止");
1394                 return false;
1395             }
1396         }
1397 
1398         /// 
1399         /// 单步执行项目成员(必须在Pause状态,即时不在Pause状态,也会先进行Pause)
1400         /// 
1401         /// 当前项目(如果项目已经开始可以为null)
1402         /// Success
1403         public bool TryNextCaseScript(CaseCell yourNode)
1404         {
1405             if (runState == CaseActuatorState.Running)
1406             {
1407                 PauseCaseScript();
1408                 myManualResetEvent.Set();
1409                 SetNowExecutiveData("单步执行>");
1410                 myManualResetEvent.Reset();
1411                 return true;
1412 
1413             }
1414             else if (runState == CaseActuatorState.Stop)
1415             {
1416                 if (RunCaseScript(yourNode))
1417                 {
1418                     PauseCaseScript();
1419                     SetNowExecutiveData("单步执行>");
1420                     myManualResetEvent.Set();
1421                     myManualResetEvent.Reset();
1422                     return true;
1423                 }
1424                 else
1425                 {
1426                     SetAndSaveNowActionError("无法进行单步执行");
1427                     return false;
1428                 }
1429             }
1430             else if (runState == CaseActuatorState.Pause)
1431             {
1432                 SetNowExecutiveData("单步执行>");
1433                 myManualResetEvent.Set();
1434                 myManualResetEvent.Reset();
1435                 return true;
1436             }
1437             else if (runState == CaseActuatorState.Running)
1438             {
1439                 SetAndSaveNowActionError("正在结束项目,无法进行单步执行");
1440                 return false;
1441             }
1442             else if (runState == CaseActuatorState.Trying)
1443             {
1444                 SetAndSaveNowActionError("存在正在执行指定项任务");
1445                 return false;
1446             }
1447             return false;
1448         }
1449 
1450         /// 
1451         /// 定项执行指定项(一直执行同一条CASE,仅在项目停止后可以使用,且goto及retry在这种任务中无效)
1452         /// 
1453         /// 定项 数据
1454         /// is Success
1455         public bool TryNowCaseScript(CaseCell yourNode)
1456         {
1457             if (runState == CaseActuatorState.Stop)
1458             {
1459                 SetRunState(CaseActuatorState.Trying);
1460                 myManualResetEvent.Set();
1461                 CreateNewActuatorTry(yourNode);
1462                 return true;
1463             }
1464             else if (runState == CaseActuatorState.Trying)
1465             {
1466                 SetAndSaveNowActionError("上一个指定项任务还未结束");
1467                 return false;
1468             }
1469             else
1470             {
1471                 SetAndSaveNowActionError("要进行定向执行前,必须先停止任务");
1472                 return false;
1473             }
1474         }
1475 
1476         /// 
1477         /// 强制关闭所有正在执行的任务(谨慎调用)
1478         /// 
1479         public void KillAll()
1480         {
1481             if (myActuatorTaskThread != null)
1482             {
1483                 if (myActuatorTaskThread.IsAlive)
1484                 {
1485                     myActuatorTaskThread.Abort();
1486                     DisconnectExecutionDevice();
1487                     SetRunState(CaseActuatorState.Stop);
1488                 }
1489             }
1490             if (myActuatorTryThread != null)
1491             {
1492                 if (myActuatorTryThread.IsAlive)
1493                 {
1494                     myActuatorTryThread.Abort();
1495                     DisconnectExecutionDevice();
1496                     SetRunState(CaseActuatorState.Stop);
1497                 }
1498             }
1499 
1500             ClearInvalidThreadList();
1501         }
1502 
1503         /// 
1504         /// 清理无效线程列表
1505         /// 
1506         private void ClearInvalidThreadList()
1507         {
1508             for (int i = invalidThreadList.Count - 1; i >= 0; i--)
1509             {
1510                 ErrorLog.PutInLog(string.Format("fing InvalidThread Name:{0}  State:{1}" , invalidThreadList[i].Name  ,invalidThreadList[i].ThreadState.ToString()));
1511                 if (invalidThreadList[i].IsAlive)
1512                 {
1513                     invalidThreadList[i].Abort();
1514                 }
1515                 else
1516                 {
1517                     invalidThreadList.Remove(invalidThreadList[i]);
1518                 }
1519             }
1520             for (int i = invalidThreadList.Count - 1; i >= 0; i--)
1521             {
1522                 if (!invalidThreadList[i].IsAlive)
1523                 {
1524                     invalidThreadList.Remove(invalidThreadList[i]);
1525                 }
1526             }
1527         }
1528 
1529         /// 
1530         /// 实现【IDisposable】强烈建议结束前调用(即时当前可用使用disconnectExecutionDevice替代)
1531         /// 
1532         public void Dispose()
1533         {
1534             KillAll();
1535             DisconnectExecutionDevice();
1536             myExecutionDeviceList.Clear();
1537             runActuatorParameterList.Clear();
1538             runActuatorStaticDataList.Clear();
1539             runTimeCaseDictionary = null;
1540             runCellProjctCollection = null;
1541             if (caseRunTime!=null)
1542             {
1543                 caseRunTime.OnLoopChangeEvent -= caseRunTime_OnLoopChangeEvent;
1544                 caseRunTime.OnQueueChangeEvent -= caseRunTime_OnQueueChangeEvent;
1545                 caseRunTime = null;
1546             }
1547            
1548         }
1549         
1550     }
View Code

 

同时CaseActionActuator还包含一个比较重要的部分myCaseProtocolEngine,该部分是协议引擎,实际上只要PC上可以使用的协议通过简单的修改都可以加入到系统

一个基于.NET平台的自动化/压力测试系统设计简述_第7张图片

对于协议引擎必须继承规定好的接口实现,然后就能将协议加入系统,具体方法见【http://www.cnblogs.com/lulianqi/p/4773268.html】

这个模块还要许多其他部分比如Case文件的解析,及其他可以自定义的内容这里就不继续讲下去了,有兴趣的可以下载完整代码。

 

辅助工具模块MyCommonTool

MyCommonTool其实包含的东西也比较多不过功能都相对独立,见下图

一个基于.NET平台的自动化/压力测试系统设计简述_第8张图片

可以看到这个模块完全是由一个个独立的类组成,相互之间的联系非常少。有很多子模块提供不同的服务通过命名也大概可以看出来VoiceService提供语音服务,myWebTool提供web服务,myEncryption提供加密服务等等,它被系统的很多模块使用。由于类比较多而又没有什么逻辑上的联系,这里同样不继续讲下去了。需要了解的可以下载完整的代码

 

 

辅助UI显示模块MyControl

这个部分主要与UI的形式与呈现有关,当然包括了很多定制的数据的banding,在AutoTest及RemoteService都会用到里面的东西。不过针对不同的界面框架这部分是不能重用的。所以也不用怎么看,稍微贴张图吧。

一个基于.NET平台的自动化/压力测试系统设计简述_第9张图片

 

主程序界面AutoTest

对于AutoTest本身已经没有太多执行相关的逻辑处理了(都由CaseExecutiveActuator来处理),其主要处理case的呈现,及执行过程中的动态修改,还包括报告的格式化输出,同时还要2个重要功能组织多个User(执行体)跟连接远程测试主机。

先稍微过下界面相关的内容,如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第10张图片                               一个基于.NET平台的自动化/压力测试系统设计简述_第11张图片

  • AutoTest                                                              这当然是主体
  • AutoTest‎.myDialogWindow                                  这里包含UI系统下的除主体外的其他UI窗口(右边的图展开了该项,可以看下)
  • AutoTest‎.myControl                                             同样是个UI控件的定制集合,不过这里的控件仅在AutoTest适合使用
  • AutoTest‎.myTool                                                  工具类,为AutoTest 的行为提供便利
  • AutoTest‎.RemoteServiceReference                     分布式远程访问模块,这个模块是引用WCF自动生成的,用于连接远程主机(这里WCF使用的自承载方式,程序运行时并不需要去配置什么其他的内容)

现在来看刚刚提到的一个重要的功能组织多个User,AutoTest可以创建任意多个虚拟执行体User,他们存储在CaseRunner中,同时CaseRunner还提供一些对User的基本的控制功能,如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第12张图片

而这个部分其实放在逻辑层更加合适,不过之前设计经验不足。把CaseRunner于UI控件十分深的banding在一起了。绑定效果如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第13张图片

这个就是大量CaseRunner绑定的效果(这个不是主界面,整体的显示效果可以看下【http://www.cnblogs.com/lulianqi/p/4773146.html】)

 

当然还有前面提到的另外一个重要功能连接远程测试主机,主要负责连接分布式部署在其他PC上的执行模块(就是后面要讲的RemoteService),同时可以控制及配置远程主机上的User(还包括连接的维持)。连接功能由RemoteClient组件来完成,它在前面提到的AutoTest‎.myTool 下,简单看下它的实现

基本结构如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第14张图片

这个其实实现起来比较简单,因为借助WCF框架,很多工作框架已经做好了,不过一些通道的选择配置以及是否适合双工通信可能不是最优的,后面还需要调整,可以看下下面的code

  1  class ExecuteServiceCallback : IExecuteServiceCallback
  2     {
  3 
  4         public ExecuteServiceCallback()
  5         {
  6 
  7         }
  8 
  9         public delegate void RunnerStateChangeEventHandler(ExecuteServiceCallback sender, RemoteRunnerInfo remoteRunnerInfo);
 10 
 11         public event RunnerStateChangeEventHandler OnRunnerStateChange;
 12 
 13         public void ReportState(RemoteRunnerInfo remoteRunnerInfo)
 14         {
 15             if (OnRunnerStateChange!=null)
 16             {
 17                 this.OnRunnerStateChange(this, remoteRunnerInfo);
 18             }
 19         }
 20     }
 21 
 22     public class RemoteClient:IDisposable
 23     {
 24 
 25         /// 
 26         /// 描述当前Client连接状态
 27         /// 
 28         public enum RemoteClientState
 29         {
 30             Connecting=0,               //正在连接
 31             Connected=1,                //连接成功
 32             Break = 2,                  //连接中断,并且正在进行重连
 33             Lost = 3                    //连接中断,且不会重新连接(必须触发重连)
 34         }
 35 
 36         ExecuteServiceClient executeServiceClient = null;
 37         InstanceContext instanceContext = null;
 38         //EndpointAddress myEp = new EndpointAddress("http://localhost:8087/SelService");
 39         EndpointAddress myEp = null;
 40 
 41         private RemoteRunner showWindow;
 42         private bool isLive = false;
 43         private RemoteClientState clientState = RemoteClientState.Lost;
 44         private int reCounectTime=5;
 45 
 46         private Thread clientLife;
 47 
 48 
 49         public delegate void RunnerStateChangeEventHandler(RemoteClient sender, RemoteRunnerInfo remoteRunnerInfo);
 50         public delegate void AllRunnerInforEventHandler(RemoteClient sender, RemoteRunnerInfo remoteRunnerInfo);
 51         public delegate void ClientStateChangeEventHandler(RemoteClient sender, RemoteClientState nowSate);
 52         public delegate void ClientErrorEventHandler(RemoteClient sender, string errorInfo);
 53 
 54         public event RunnerStateChangeEventHandler OnRunnerStateChange;
 55         public event AllRunnerInforEventHandler OnPutAllRunnerInfor;
 56         public event ClientStateChangeEventHandler OnClientStateChange;
 57         public event ClientErrorEventHandler OnClientErrorInfor;
 58 
 59         
 60 
 61         public RemoteClient(EndpointAddress yourEp, RemoteRunner yourWindow )
 62         {
 63             myEp = yourEp;
 64             showWindow = yourWindow;
 65         }
 66 
 67         public override string ToString()
 68         {
 69             if (myEp != null)
 70             {
 71                 return myEp.Uri.Host + ":" + myEp.Uri.Port;
 72             }
 73             else
 74             {
 75                 return "Null Ep";
 76             }
 77         }
 78 
 79         /// 
 80         /// 获取或设置RemoteClient 的基础地址
 81         /// 
 82         public EndpointAddress ClientEp
 83         {
 84             get { return myEp;}
 85             set { myEp = value; }
 86         }
 87 
 88         /// 
 89         /// 获取或设置ShowWindow
 90         /// 
 91         public RemoteRunner ShowWindow
 92         {
 93             get { return showWindow; }
 94             set { showWindow = value; }
 95         }
 96 
 97         /// 
 98         /// 获取当前Client连接状态(自维护状态,该状态同时提示生命线程运行情况)
 99         /// 
100         public RemoteClientState ClientState
101         {
102             get { return clientState; }
103         }
104 
105         /// 
106         /// 获取当前executeServiceClient通道状态
107         /// 
108         public CommunicationState  ExecuteServiceClientState
109         {
110             get 
111             {
112                 if (executeServiceClient==null)
113                 {
114                     return CommunicationState.Closed;
115                 }
116                 return executeServiceClient.State; 
117             }
118         }
119 
120         /// 
121         /// 获取或设置断线重连次数限制
122         /// 
123         public int ReCounectTime
124         {
125             get { return reCounectTime; }
126             set { reCounectTime = value; }
127         }
128 
129         /// 
130         /// 报告当前Client所有Runner状态
131         /// 
132         /// 
133         private void PutAllRunnerInfor(RemoteRunnerInfo remoteRunnerInfo)
134         {
135             if (OnPutAllRunnerInfor != null)
136             {
137                 this.OnPutAllRunnerInfor(this, remoteRunnerInfo);
138             }
139             if (showWindow != null)
140             {
141                 showWindow.RefreshRemoteRunnerView(remoteRunnerInfo);
142             }       
143         }
144 
145         /// 
146         /// 改变连接状态
147         /// 
148         private void SetClientState(RemoteClientState nowState)
149         {
150             clientState = nowState;
151             if (OnClientStateChange != null)
152             {
153                 this.OnClientStateChange(this, nowState);
154             }
155         }
156 
157         /// 
158         /// 向订阅者报告错误信息
159         /// 
160         /// 错误信息
161         private void SetClientErrorInfo(string errorInfo)
162         {
163             if(errorInfo!=null && OnClientErrorInfor!=null)
164             {
165                 this.OnClientErrorInfor(this, errorInfo);
166             }
167         }
168 
169         /// 
170         /// 创建一个【ExecuteServiceClient】实例
171         /// 
172         /// 【ExecuteServiceClient】实例
173         private ExecuteServiceClient RestartClient()
174         {
175             if (instanceContext==null)
176             {
177                 //InstanceContext
178                 ExecuteServiceCallback executeServiceCallback = new ExecuteServiceCallback();
179                 executeServiceCallback.OnRunnerStateChange += executeServiceCallback_OnRunnerStateChange;
180                 instanceContext = new InstanceContext(executeServiceCallback);
181                 //Binding
182                 System.ServiceModel.Channels.Binding binding = new WSDualHttpBinding();
183                 ((System.ServiceModel.WSDualHttpBinding)(binding)).Security.Mode = WSDualHttpSecurityMode.None;
184                 ((System.ServiceModel.WSDualHttpBinding)(binding)).Security.Message.ClientCredentialType = MessageCredentialType.UserName;
185                 binding.SendTimeout = new TimeSpan(0, 0, 10);
186                 binding.OpenTimeout = new TimeSpan(0, 0, 10);
187                 binding.ReceiveTimeout = new TimeSpan(0, 0, 10);
188 
189                 System.ServiceModel.Channels.Binding tcpBinding = new NetTcpBinding();
190                 ((System.ServiceModel.NetTcpBinding)(tcpBinding)).Security.Mode = SecurityMode.None;
191                 ((System.ServiceModel.NetTcpBinding)(tcpBinding)).Security.Message.ClientCredentialType = MessageCredentialType.UserName;
192                 tcpBinding.SendTimeout = new TimeSpan(0, 0, 10);
193                 tcpBinding.OpenTimeout = new TimeSpan(0, 0, 10);
194                 tcpBinding.ReceiveTimeout = new TimeSpan(0, 0, 10);
195 
196                 executeServiceClient = new ExecuteServiceClient(instanceContext, binding, myEp);
197                 //executeServiceClient = new ExecuteServiceClient(instanceContext, new WSDualHttpBinding(), myEp);
198 
199                 instanceContext.Closed += instanceContext_Closed;
200                 instanceContext.Opened += instanceContext_Opened;
201                 return executeServiceClient;
202             }
203             else
204             {
205                 instanceContext.Closed -= instanceContext_Closed;
206                 instanceContext.Opened -= instanceContext_Opened;
207                 instanceContext = null;
208                 return RestartClient();
209             }
210         }
211 
212         #region RestartClient通信
213         
214         /// 
215         /// 处理收到的双工回调(仅报告有变化的Runner)
216         /// 
217         void executeServiceCallback_OnRunnerStateChange(ExecuteServiceCallback sender, RemoteRunnerInfo remoteRunnerInfo)
218         {
219             if(OnRunnerStateChange!=null)
220             {
221                 this.OnRunnerStateChange(this, remoteRunnerInfo);
222             }
223             if (remoteRunnerInfo == null)
224             {
225                 if (showWindow != null)
226                 {
227                     showWindow.ShowError("Null Data" + "\r\n");
228                 }
229                 return;
230             }
231             if (remoteRunnerInfo.RunnerStateList != null)
232             {
233                 if (showWindow != null)
234                 {
235                     showWindow.UpdataRemoteRunnerView(remoteRunnerInfo);
236                 }
237             }
238         }
239 
240         /// 
241         /// 获取当前Client所有Runner状态
242         /// 
243         public void GetAllRunnerInfor()
244         {
245             if (ExecuteServiceClientState == CommunicationState.Opened)
246             {
247                 try
248                 {
249                     RemoteRunnerInfo nowRemoteRunnerInfo = executeServiceClient.GetAllRunnerSate();
250                     if (nowRemoteRunnerInfo != null)
251                     {
252                         PutAllRunnerInfor(nowRemoteRunnerInfo);
253                     }
254                 }
255                 catch (Exception ex)
256                 {
257                     SetClientErrorInfo(ex.Message);
258                 }
259             }
260             else
261             {
262                 SetClientErrorInfo("连接未打开");
263             }
264         }
265 
266         /// 
267         /// 获取当前Client所有Runner状态(提供内部使用,不会捕捉错误)
268         /// 
269         private void GetAllRunnerInforEx()
270         {
271             RemoteRunnerInfo nowRemoteRunnerInfo = executeServiceClient.GetAllRunnerSate();
272             if (nowRemoteRunnerInfo != null)
273             {
274                 PutAllRunnerInfor(nowRemoteRunnerInfo);
275             }
276         }
277 
278         /// 
279         /// 启动指定执行器
280         /// 
281         /// 执行器列表
282         public void StartRunner(List<int> runnerList)
283         {
284             if (ExecuteServiceClientState == CommunicationState.Opened)
285             {
286                 try
287                 {
288                     executeServiceClient.StartRunner(runnerList.ToArray());
289                 }
290                 catch (Exception ex)
291                 {
292                     SetClientErrorInfo(ex.Message);
293                 }
294             }
295             else
296             {
297                 SetClientErrorInfo("连接未打开");
298             }
299         }
300 
301         /// 
302         /// 暂停指定执行器
303         /// 
304         /// 执行器列表
305         public void PauseRunner(List<int> runnerList)
306         {
307             if (ExecuteServiceClientState == CommunicationState.Opened)
308             {
309                 try
310                 {
311                     executeServiceClient.PauseRunner(runnerList.ToArray());
312                 }
313                 catch (Exception ex)
314                 {
315                     SetClientErrorInfo(ex.Message);
316                 }
317             }
318             else
319             {
320                 SetClientErrorInfo("连接未打开");
321             }
322         }
323 
324         /// 
325         /// 停止指定执行器
326         /// 
327         /// 执行器列表
328         public void StopRunner(List<int> runnerList)
329         {
330             if (ExecuteServiceClientState == CommunicationState.Opened)
331             {
332                 try
333                 {
334                     executeServiceClient.StopRunner(runnerList.ToArray());
335                 }
336                 catch(Exception ex)
337                 {
338                     SetClientErrorInfo(ex.Message);
339                 }
340             }
341             else
342             {
343                 SetClientErrorInfo("连接未打开");
344             }
345         }
346 
347         #endregion
348 
349 
350         private void instanceContext_Closed(object sender, EventArgs e)
351         {
352             
353         }
354 
355         void instanceContext_Opened(object sender, EventArgs e)
356         {
357             
358         }
359 
360         /// 
361         /// 启动当前Client
362         /// 
363         public void StartClient()
364         {
365             //Thread myThreadTest = new Thread(new ThreadStart(ExecutiveActuatorTask),10240);
366             if (clientLife != null)
367             {
368                 if (clientLife.IsAlive)
369                 {
370                     if (showWindow != null)
371                     {
372                         showWindow.ShowError("IsAlive");
373                     }
374                 }
375                 else
376                 {
377                     clientLife = null;
378                     StartClient();
379                 }
380             }
381             else
382             {
383                 clientLife = new Thread(new ParameterizedThreadStart(ClientAliveTask));
384                 clientLife.Name = "ClientLife" + myEp.ToString();
385                 clientLife.Priority = ThreadPriority.Normal;
386                 clientLife.IsBackground = true;
387                 isLive = true;
388                 clientLife.Start(executeServiceClient);
389             }
390         }
391 
392         /// 
393         /// 停止当前Client
394         /// 
395         public void StopClient()
396         {
397             isLive = false;
398         }
399 
400 
401         /// 
402         /// 保持连接的心跳及重新连接的线程任务
403         /// 
404         private void ClientAliveTask(object yourExecuteClient)
405         {
406             ExecuteServiceClient executeClient = (ExecuteServiceClient)yourExecuteClient;
407             int counectTime = reCounectTime;
408 
409             ReConnect:
410             executeClient = RestartClient();
411             try
412             {
413                 SetClientState(RemoteClientState.Connecting);
414                 GetAllRunnerInforEx();
415                 SetClientState(RemoteClientState.Connected);
416             }
417             catch (Exception ex)
418             {
419                 MyCommonTool.ErrorLog.PutInLogEx(ex);
420                 if (counectTime > 0 && isLive)
421                 {
422                     counectTime--;
423                     SetClientState(RemoteClientState.Break);
424                     Thread.Sleep(2000);
425                     goto ReConnect;
426                 }
427                 else
428                 {
429                     StopClient();
430                 }
431             }
432 
433             while (isLive)
434             {
435                 try
436                 {
437                     executeClient.ExecuteServiceBeat();
438                 }
439                 catch (Exception ex)
440                 {
441                     SetClientState(RemoteClientState.Break);
442                     Thread.Sleep(2000);
443                     MyCommonTool.ErrorLog.PutInLogEx(ex);
444                     counectTime = reCounectTime;
445                     goto ReConnect;
446                 }
447                 Thread.Sleep(10000);
448             }
449 
450             SetClientState(RemoteClientState.Lost);
451         }
452 
453         public void Dispose()
454         {
455             if (clientLife != null)
456             {
457                 if (clientLife.IsAlive)
458                 {
459                     clientLife.Abort();
460                 }
461             }
462             executeServiceClient = null;
463             instanceContext = null;
464         }
465     }
466 }
View Code

 

分布式部署服务模块RemoteService

这个部分与AutoTest整体结构是相似的,在执行逻辑上也是同样依靠逻辑层的3个主要模块。而内部基于WCF单独实现了服务部分,服务内容主要包括对状态及业务返回数据进行过滤重组然后上报给连接的控制机,还有接收及处理控制机的控制或配置等命令请求。

下面看一下自身的结构,如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第15张图片

 

可以看到结构上与AutoTest确实是大体一致的,主要看下跟分布式部署相关的2个组件

  • ExecuteService             直接提供服务说需要的部分(是WCF的必要部分)
  • ServerHost                    对服务连接的抽象再封装,所有对服务的操作,包括获取服务数据都通过这个组件,下层应用不直接使用ExecuteService服务(从结构关系图中也可以看出来ExecuteService只被ServerHost调用)

 其他部分与远程服务没有太大关系的就不介绍了

 

ExecuteService 按要求实现IExecuteService接口,结构跟逻辑都比较清晰(现在这部分的设计十分简单,后期对服务内容的控制也只需要改动这个地方就可以了),直接看下下面的结构图

一个基于.NET平台的自动化/压力测试系统设计简述_第16张图片

 

ServerHost 其实就是对ExecuteService再一层的封装,加入了许多与执行数据相关的逻辑,以方便应用层面的直接调用,如下图

一个基于.NET平台的自动化/压力测试系统设计简述_第17张图片

如上图,订阅了多个回调委托来获取数据,在内部进行处理(MessageTransferChannel_RunnerCommandCallback,MessageTransferChannel_GetAllRemoteRunnerInfoCallback),同时也定义了许多委托抛出数据给应用使用,同时还需要介绍应用的命令处理后转发给ExecuteService,当然还有一个重要的功能,服务的启动跟维持也在这里完成。下面是这个类code的具体实现

  1  class ServerHost
  2     {
  3         Uri baseAddress = new Uri("http://localhost:8087/SelService");//初始默认值在运行时由设置值来决定
  4         ServiceHost baseHost = null;
  5 
  6         public delegate void ServerHostMessageEventHandler(string sender, string message);
  7         public event ServerHostMessageEventHandler OnServerHostMessage;
  8 
  9         public delegate List BackNowRunnerListEventHandler();
 10         public event BackNowRunnerListEventHandler OnBackNowRunnerList;
 11 
 12         //public delegate void ServerHostCommandEventHandler(RunnerCommand command, List runners);
 13         //public event ServerHostCommandEventHandler OnServerHostCommand;
 14 
 15         /// 
 16         /// 获取或设置当前BaseAddress
 17         /// 
 18         public Uri BaseAddress
 19         {
 20             get { return baseAddress; }
 21             set { baseAddress = value; }
 22         }
 23 
 24         /// 
 25         /// 获取当前BaseHost
 26         /// 
 27         public ServiceHost BaseHost
 28         {
 29             get { return baseHost; }
 30         }
 31 
 32         /// 
 33         /// 获取BaseHost当前连接状态
 34         /// 
 35         public CommunicationState BaseHostState
 36         {
 37             get
 38             {
 39                 if (baseHost == null)
 40                 {
 41                     return CommunicationState.Closed;
 42                 }
 43                 else
 44                 {
 45                     return baseHost.State;
 46                 }
 47             }
 48         }
 49 
 50         /// 
 51         /// 初始化ServerHost
 52         /// 
 53         /// 
 54         public ServerHost(Uri yourBaseAddress)
 55         {
 56             baseAddress = yourBaseAddress;
 57             MessageTransferChannel.MessageCallback += new Action<object, string>((a, b) => AddInfo(b));
 58 
 59             MessageTransferChannel.OnRunnerCommand += MessageTransferChannel_RunnerCommandCallback;
 60             MessageTransferChannel.OnGetAllRemoteRunnerInfo += MessageTransferChannel_GetAllRemoteRunnerInfoCallback;
 61         }
 62 
 63         /// 
 64         /// 处理ExecuteService的远程指令【runner状态获取】
 65         /// 
 66         RemoteRunnerInfo MessageTransferChannel_GetAllRemoteRunnerInfoCallback()
 67         {
 68             List caseRunnerList = CaseRunnerList;
 69             if (caseRunnerList == null)
 70             {
 71                 return new RemoteRunnerInfo();
 72             }
 73             return GetRunnerInfo(caseRunnerList, true);
 74         }
 75 
 76         /// 
 77         /// 处理ExecuteService的远程指令【runner控制】
 78         /// 
 79         void MessageTransferChannel_RunnerCommandCallback(ExecuteService sender, RunnerCommand command, List<int> runners)
 80         {
 81             List caseRunnerList=CaseRunnerList;
 82             if(caseRunnerList==null)
 83             {
 84                 return;
 85             }
 86             RunnerCommandExecute(caseRunnerList, command, runners);
 87         }
 88 
 89         /// 
 90         /// 触发更新CaseRunner状态双工回调(局部更新)
 91         /// 
 92         /// CaseRunner 列表
 93         public void SendStateCallBack(List caseRunnerList)
 94         {
 95             SendStateInfo(caseRunnerList, false);
 96         }
 97 
 98         /// 
 99         /// 触发更新CaseRunner状态双工回调(全部更新)
100         /// 
101         /// CaseRunner 列表
102         public void SendAllStateCallBack(List caseRunnerList)
103         {
104             SendStateInfo(caseRunnerList, true);
105         }
106 
107         /// 
108         /// 像执行行体请求CaseRunner 最新列表
109         /// 
110         private List CaseRunnerList
111         {
112             get
113             {
114                 if (OnBackNowRunnerList() != null)
115                 {
116                     return OnBackNowRunnerList();
117                 }
118                 return null;
119             }
120         }
121 
122         /// 
123         /// 输出提示信息
124         /// 
125         /// 
126         private void AddInfo(string message)
127         {
128             if(OnServerHostMessage!=null)
129             {
130                 this.OnServerHostMessage("baseHost", message);
131             }
132         }
133 
134         /// 
135         /// 启动BaseHost
136         /// 
137         public void OpenBaseHost()
138         {
139             if (baseHost == null)
140             {
141                 baseHost = new ServiceHost(typeof(ExecuteService), baseAddress);
142 
143                 ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
144                 smb.HttpGetEnabled = true;
145                 smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
146 
147                 baseHost.Description.Behaviors.Add(smb);
148                 //baseHost.AddServiceEndpoint(typeof(IExecuteService), new BasicHttpBinding(), "");
149                 //baseHost.AddServiceEndpoint(typeof(IExecuteService), new WSDualHttpBinding(), "");
150 
151                 System.ServiceModel.Channels.Binding binding = new WSDualHttpBinding();
152                 ((System.ServiceModel.WSDualHttpBinding)(binding)).Security.Mode = WSDualHttpSecurityMode.None;
153                 ((System.ServiceModel.WSDualHttpBinding)(binding)).Security.Message.ClientCredentialType = MessageCredentialType.UserName;
154 
155                 System.ServiceModel.Channels.Binding tcpBinding = new NetTcpBinding();
156                 ((System.ServiceModel.NetTcpBinding)(tcpBinding)).Security.Mode = SecurityMode.None;
157                 ((System.ServiceModel.NetTcpBinding)(tcpBinding)).Security.Message.ClientCredentialType = MessageCredentialType.UserName;
158 
159                 //测试开安全双工只能在本机使用
160                 baseHost.AddServiceEndpoint(typeof(IExecuteService), binding, "");
161 
162                 baseHost.Opening += new EventHandler((yourObject, yourEventAgrs) => AddInfo("Opening"));
163                 baseHost.Opened += new EventHandler((yourObject, yourEventAgrs) => AddInfo("Opened"));
164                 baseHost.Closed += new EventHandler((yourObject, yourEventAgrs) => AddInfo("Closed"));
165                 baseHost.Closing += new EventHandler((yourObject, yourEventAgrs) => AddInfo("Closing"));
166                 baseHost.Faulted += new EventHandler((yourObject, yourEventAgrs) => AddInfo("Faulted"));
167 
168 
169                 Thread openBaseThread = new Thread(new ThreadStart(BaseHostOpen));
170                 openBaseThread.IsBackground = true;
171                 openBaseThread.Start();
172               
173             }
174             else
175             {
176                 if (baseHost.State == CommunicationState.Opened)
177                 {
178                     AddInfo("服务已经开启");
179                 }
180                 else if (baseHost.State == CommunicationState.Opening)
181                 {
182                     AddInfo("服务正在开启");
183                 }
184                 else
185                 {
186                     baseHost.Abort();
187                     baseHost = null;
188                     OpenBaseHost();
189                 }
190             }
191         }
192 
193         private void BaseHostOpen()
194         {
195             try
196             {
197                 baseHost.Open();
198             }
199             catch (Exception ex)
200             {
201                 AddInfo(ex.Message);
202             }
203         }
204 
205         /// 
206         /// 关闭BaseHost
207         /// 
208         public void CloseBaseHost()
209         {
210             if (baseHost == null)
211             {
212                 AddInfo("未发现服务");
213             }
214             else
215             {
216                 if (baseHost.State != CommunicationState.Closed)
217                 {
218                     AddInfo(baseAddress.ToString() + "服务关闭");
219                     baseHost.Close();
220                 }
221                 else
222                 {
223                     AddInfo(baseAddress.ToString() + "服务已经关闭");
224                 }
225             }
226         }
227 
228 
229         /// 
230         /// 执行远程命令
231         /// 
232         /// CaseRunner 列表
233         /// 命令类型
234         /// 受影响Runner
235         private void RunnerCommandExecute(List caseRunnerList, RunnerCommand command, List<int> Runners)
236         {
237             switch (command)
238             {
239                 case RunnerCommand.Start:
240                     if (Runners != null)
241                     {
242                         if (Runners.Count > 0)
243                         {
244                             foreach (int tempRunnerIndex in Runners)
245                             {
246                                 if (caseRunnerList.Count >= tempRunnerIndex)
247                                 {
248                                     caseRunnerList[tempRunnerIndex].RunQuiet();
249                                 }
250                                 else
251                                 {
252                                     AddInfo("tempRunnerIndex error");
253                                 }
254                             }
255                         }
256                     }
257                     else
258                     {
259                         AddInfo("Runners is null");
260                     }
261                     break;
262                 case RunnerCommand.Stop:
263                     if (Runners != null)
264                     {
265                         if (Runners.Count > 0)
266                         {
267                             foreach (int tempRunnerIndex in Runners)
268                             {
269                                 if (caseRunnerList.Count >= tempRunnerIndex)
270                                 {
271                                     caseRunnerList[tempRunnerIndex].StopQuiet();
272                                 }
273                                 else
274                                 {
275                                     AddInfo("tempRunnerIndex error");
276                                 }
277                             }
278                         }
279                     }
280                     else
281                     {
282                         AddInfo("Runners is null");
283                     }
284                     break;
285                 case RunnerCommand.Pause:
286                     if (Runners != null)
287                     {
288                         if (Runners.Count > 0)
289                         {
290                             foreach (int tempRunnerIndex in Runners)
291                             {
292                                 if (caseRunnerList.Count >= tempRunnerIndex)
293                                 {
294                                     caseRunnerList[tempRunnerIndex].PauseQuiet();
295                                 }
296                                 else
297                                 {
298                                     AddInfo("tempRunnerIndex error");
299                                 }
300                             }
301                         }
302                     }
303                     else
304                     {
305                         AddInfo("Runners is null");
306                     }
307                     break;
308                 default:
309                     break;
310             }
311         }
312 
313         /// 
314         /// 触发更新CaseRunner状态双工回调
315         /// 
316         /// CaseRunner 列表
317         /// 是否全部更新
318         private void SendStateInfo(List caseRunnerList,bool isAll)
319         {
320             if (BaseHostState != CommunicationState.Opened)
321             {
322                 return;
323             }
324             if (caseRunnerList.Count > 0)
325             {
326                 RemoteRunnerInfo remoteRunnerInfo = GetRunnerInfo(caseRunnerList,isAll);
327                 if (remoteRunnerInfo.RunnerStateList != null)
328                 {
329                     if (remoteRunnerInfo.RunnerStateList.Count > 0)
330                     {
331                         if (MessageTransferChannel.OnRunnerInfoCallback != null)
332                         {
333                             MessageTransferChannel.OnRunnerInfoCallback(remoteRunnerInfo);
334                         }
335                     }
336                 }
337             }
338         }
339 
340         /// 
341         /// 获取List中的更新信息
342         /// 
343         /// CaseRunner 列表
344         /// T表示全部更新,F标识局部更新
345         /// 更新信息
346         private RemoteRunnerInfo GetRunnerInfo(List runnerList, bool isUpdataAll)
347         {
348             RemoteRunnerInfo remoteRunnerInfo = new RemoteRunnerInfo();
349             if (runnerList == null)
350             {
351                 return null;
352             }
353             foreach (CaseRunner tempRunner in runnerList)
354             {
355                 if (tempRunner.IsNeedUpdata || isUpdataAll)
356                 {
357                     tempRunner.IsNeedUpdata = false;
358 
359                     RunnerState tempRunnerState = new RunnerState();
360                     if (tempRunner.RunerActuator.NowExecutionResultList != null)
361                     {
362                         if (tempRunner.RunerActuator.NowExecutionResultList.Count > 0)
363                         {
364                             myExecutionDeviceResult tempResult = tempRunner.RunerActuator.NowExecutionResultList[tempRunner.RunerActuator.NowExecutionResultList.Count - 1];
365                             tempRunnerState.RunnerID = runnerList.IndexOf(tempRunner);
366                             tempRunnerState.RunnerName = tempRunner.RunnerName;
367                             tempRunnerState.NowCell = tempResult.caseId.ToString();
368                             tempRunnerState.CellResult = tempResult.result.ToString();
369                             tempRunnerState.State = tempRunner.RunnerState.ToString();
370                             tempRunnerState.Time = tempResult.spanTime;
371                             tempRunnerState.RunDetails = tempResult.backContent;
372                             tempRunnerState.RunnerProgress = tempRunner.RunerActuator.RunProgress;
373                             remoteRunnerInfo.AddRunnerState(tempRunnerState);
374                         }
375                         else if (isUpdataAll)
376                         {
377                             tempRunnerState.RunnerID = runnerList.IndexOf(tempRunner);
378                             tempRunnerState.RunnerName = tempRunner.RunnerName;
379                             tempRunnerState.NowCell = "";
380                             tempRunnerState.CellResult = "";
381                             tempRunnerState.State = tempRunner.RunnerState.ToString();
382                             tempRunnerState.Time = "";
383                             tempRunnerState.RunDetails = "";
384                             tempRunnerState.RunnerProgress = tempRunner.RunerActuator.RunProgress;
385                             remoteRunnerInfo.AddRunnerState(tempRunnerState);
386                         }
387                         else
388                         {
389                             tempRunnerState.RunnerID = runnerList.IndexOf(tempRunner);
390                             tempRunnerState.RunnerName = tempRunner.RunnerName;
391                             tempRunnerState.State = tempRunner.RunnerState.ToString();
392                             tempRunnerState.RunnerProgress = tempRunner.RunerActuator.RunProgress;
393                             remoteRunnerInfo.AddRunnerState(tempRunnerState);
394                         }
395                     }
396                 }
397             }
398             return remoteRunnerInfo;
399         }
400 
401         /// 
402         /// 获取List中的更新信息(局部更新)
403         /// 
404         /// CaseRunner 列表
405         /// 更新信息
406         private RemoteRunnerInfo GetRunnerInfo(List runnerList)
407         {
408             return GetRunnerInfo(runnerList, false);
409         }
410 
411     }
View Code

 

最后放几个动画,简单演示下Auto组件的部分功能

  

 

 

 

系统代码打包下载  AutoTest_V5.3_CodeOnly.rar

 

你可能感兴趣的:(一个基于.NET平台的自动化/压力测试系统设计简述)