发布新日志

  • 基于PostSharp的AOP框架设计 .

    2012-09-12 09:20:13

    1. AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。   
    2.   
    3. 在Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。   
    4.   
    5. 前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;   
    6.   
    7. 早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhen的PostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:   
    8.   
    9. 和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。   
    10.   
    11. 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。   
    12. 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。   
    13. 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。   
    14. 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。   
    15. 还可以拦截 Field Access、Exception 等操作。   
    16. 无需将对象创建代码改成 "new proxy()",更加透明。   
    17. 可以使用通配符进行多重拦截匹配。   
    18. 静态注入带来的问题更多的是注入代码的质量和调试复杂度。   
    19. 另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。   
    20.   
    21. 我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;   
    22.   
    23. 按以前的写法我们可能很麻烦,我们要如此这般的写:   
    24.   
    25. public class XOrders  
    26.     {  
    27.         public bool Add(string id, string orderName)  
    28.         {  
    29.             try  
    30.             {  
    31.                 if (User.AddEnable)  
    32.                 {  
    33.                     //TODO:新增订单的实现   
    34.                     Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
    35.                     Console.ReadLine();  
    36.                     Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
    37.                     return true;  
    38.                 }  
    39.                 else  
    40.                 {  
    41.                     //   
    42.                 }  
    43.             }  
    44.             catch (Exception)  
    45.             {  
    46.                 //TODO:记录异常的实现   
    47.                 throw;  
    48.             }   
    49.   
    50.             return true;   
    51.   
    52.         }   
    53.   
    54.         public bool Delete(string id)  
    55.         {  
    56.             try  
    57.             {  
    58.                 if (User.DeleteEnable)  
    59.                 {  
    60.                     //TODO:删除订单的实现   
    61.                     Console.WriteLine("您删除订单成功:编号:{0}", id);  
    62.                 }  
    63.                 else  
    64.                 {  
    65.                     //   
    66.                 }   
    67.   
    68.             }  
    69.             catch (Exception)  
    70.             {  
    71.                 //TODO:记录异常的实现   
    72.                 throw;  
    73.             }   
    74.   
    75.             return true;  
    76.         }   
    77.   
    78. 这种写的弊端我就不多说了,有很多先驱都阐述过……   
    79.   
    80. 我要演示的是采用AOP技术的框架原型实现:   
    81.   
    82. 首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)   
    83.   
    84. 然后我们实现Orders对象   
    85.   
    86. using System;   
    87.   
    88. namespace PostSharp.Demo  
    89. {  
    90.     public class Orders  
    91.     {  
    92.         [Permission]  
    93.         [Exception]  
    94.         public bool Add(string id, string orderName)  
    95.         {  
    96.             Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
    97.             Console.ReadLine();  
    98.             Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
    99.             return true;  
    100.         }   
    101.   
    102.         [Logger]  
    103.         [Permission]  
    104.         [Exception]  
    105.         public bool Delete(string id)  
    106.         {  
    107.             Console.WriteLine("您删除订单成功:编号:{0}", id);   
    108.   
    109.             return true;  
    110.         }  
    111.     }  
    112. }   
    113.   
    114. 当然还要模拟一个用户资格认证   
    115.   
    116. namespace PostSharp.Demo  
    117. {  
    118.     /// <summary>   
    119.     /// 静态的用户对象,用于存放当前登录用户,成员资格   
    120.     /// </summary>   
    121.     public static class User  
    122.     {  
    123.         private static string _userId;   
    124.   
    125.         public static string UserId  
    126.         {  
    127.             get { return _userId; }  
    128.             set { _userId = value; }  
    129.         }   
    130.   
    131.         public static bool AddEnable  
    132.         {  
    133.             get  
    134.             {  
    135.                 return (_userId.ToLower() == "admin");  
    136.             }  
    137.         }   
    138.   
    139.         public static bool DeleteEnable  
    140.         {  
    141.             get  
    142.             {  
    143.                 return (_userId.ToLower() == "admin");  
    144.             }  
    145.         }  
    146.     }  
    147. }   
    148.   
    149. 再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……   
    150.   
    151. PermissionAttribute   
    152.   
    153. using System;  
    154. using PostSharp.Laos;   
    155.   
    156. namespace PostSharp.Demo  
    157. {  
    158.     [Serializable]  
    159.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
    160.     public class PermissionAttribute : OnMethodBoundaryAspect  
    161.     {  
    162.         public override void OnEntry(MethodExecutionEventArgs eventArgs)  
    163.         {  
    164.             if (!User.AddEnable)  
    165.             {  
    166.                 Console.WriteLine("用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);  
    167.                 eventArgs.FlowBehavior = FlowBehavior.Return;  
    168.             }   
    169.   
    170.         }  
    171.     }  
    172. }   
    173.   
    174. LoggerAttribute   
    175.   
    176. using System;  
    177. using PostSharp.Laos;   
    178.   
    179. namespace PostSharp.Demo  
    180. {  
    181.     [Serializable]  
    182.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
    183.     public sealed class LoggerAttribute : OnMethodInvocationAspect  
    184.     {  
    185.         public override void OnInvocation(MethodInvocationEventArgs eventArgs)  
    186.         {  
    187.             DateTime time = DateTime.Now;  
    188.             string log = "时间:{0},操作人员:{1},操作:{2}!";   
    189.   
    190.             object[] arg = eventArgs.GetArguments();   
    191.   
    192.             log = String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!");   
    193.   
    194.             System.IO.File.WriteAllText("C://Log.Txt", log);  
    195.         }  
    196.     }  
    197. }   
    198.   
    199. ExceptionAttribute   
    200.   
    201. using System;  
    202. using PostSharp.Laos;   
    203.   
    204. namespace PostSharp.Demo  
    205. {  
    206.     [Serializable]  
    207.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
    208.     public class ExceptionAttribute : OnExceptionAspect  
    209.     {  
    210.         public override void OnException(MethodExecutionEventArgs eventArgs)  
    211.         {  
    212.             Console.WriteLine("程序出现异常:{0}", eventArgs.Exception.Message);  
    213.             eventArgs.FlowBehavior = FlowBehavior.Return;  
    214.         }  
    215.     }  
    216. }   
    217.   
    218.     
    219.   
    220. 然后再用控制台程序测试下能不能成功   
    221.   
    222. Orders order = new Orders();  
    223.             Console.WriteLine("请输入用户名:");  
    224.             User.UserId = Console.ReadLine();  
    225.             Console.WriteLine("请输入密码:");  
    226.             Console.ReadLine();  
    227.             string id;   
    228.   
    229.             LRedo:  
    230.             Console.WriteLine("请输入您要执行的操作:新增(A),删除(D),退出(X)");   
    231.   
    232.             string opt = Console.ReadLine();   
    233.   
    234.             if (opt.ToLower() == "a")  
    235.             {  
    236.                 Console.WriteLine("请输入订单编号:");  
    237.                 id = Console.ReadLine();   
    238.   
    239.                 Console.WriteLine("请输入订单名称:");  
    240.                 string name = Console.ReadLine();  
    241.                 order.Add(id, name);  
    242.             }  
    243.             else if (opt.ToLower() == "d")  
    244.             {  
    245.                 Console.WriteLine("请输入订单编号:");  
    246.                 id = Console.ReadLine();  
    247.                 order.Delete(id);  
    248.             }  
    249.             else if (opt.ToLower() == "x")  
    250.             {  
    251.             }  
    252.             else  
    253.             {  
    254.                 Console.WriteLine("您的输入不正确,请重新输入!");  
    255.                 goto LRedo;  
    256.             }   
    257.   
    258.             Console.WriteLine("按任意键退出……");  
    259.             Console.ReadLine();   
    260.   
    261. 写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?   
    262.   
    263. public class Orders  
    264. {  
    265.     // Methods   
    266.     static Orders()  
    267.     {  
    268.         if (!~PostSharp~Laos~Implementation.initialized)  
    269.         {  
    270.             LaosNotInitializedException.Throw();  
    271.         }  
    272.         ~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);  
    273.         ~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);  
    274.         ~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);  
    275.         ~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);  
    276.         ~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);  
    277.         ~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);  
    278.         ~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);  
    279.         ~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);  
    280.         ~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);  
    281.         ~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);  
    282.     }   
    283.   
    284.     private bool ~Delete(string id)  
    285.     {  
    286.         Console.WriteLine("您删除订单成功:编号:{0}", id);  
    287.         return true;  
    288.     }   
    289.   
    290.     public bool Add(string id, string orderName)  
    291.     {  
    292.         bool ~returnValue~1;  
    293.         MethodExecutionEventArgs ~laosEventArgs~7;  
    294.         try  
    295.         {  
    296.             object[] ~arguments~6 = new object[] { id, orderName };  
    297.             ~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~6);  
    298.             ~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);  
    299.             if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)  
    300.             {  
    301.                 return (bool) ~laosEventArgs~7.ReturnValue;  
    302.             }  
    303.             try  
    304.             {  
    305.                 Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
    306.                 Console.ReadLine();  
    307.                 Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
    308.                 ~returnValue~1 = true;  
    309.             }  
    310.             catch (Exception ~exception~2)  
    311.             {  
    312.                 object[] ~arguments~3 = new object[] { id, orderName };  
    313.                 MethodExecutionEventArgs ~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~3);  
    314.                 ~laosEventArgs~4.Exception = ~exception~2;  
    315.                 ~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);  
    316.                 switch (~laosEventArgs~4.FlowBehavior)  
    317.                 {  
    318.                     case FlowBehavior.Continue:  
    319.                         goto Label_0145;   
    320.   
    321.                     case FlowBehavior.Return:  
    322.                         ~returnValue~1 = (bool) ~laosEventArgs~4.ReturnValue;  
    323.                         goto Label_0145;  
    324.                 }  
    325.                 throw;  
    326.             }  
    327.         Label_0145:  
    328.             ~laosEventArgs~7.ReturnValue = ~returnValue~1;  
    329.             ~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);  
    330.             ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;  
    331.         }  
    332.         catch (Exception ~exception~5)  
    333.         {  
    334.             ~laosEventArgs~7.Exception = ~exception~5;  
    335.             ~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);  
    336.             switch (~laosEventArgs~7.FlowBehavior)  
    337.             {  
    338.                 case FlowBehavior.Continue:  
    339.                     return ~returnValue~1;   
    340.   
    341.                 case FlowBehavior.Return:  
    342.                     return (bool) ~laosEventArgs~7.ReturnValue;  
    343.             }  
    344.             throw;  
    345.         }  
    346.         finally  
    347.         {  
    348.             ~laosEventArgs~7.ReturnValue = ~returnValue~1;  
    349.             ~PostSharp~Laos~Implementation.~aspect~1.OnExit(~laosEventArgs~7);  
    350.             ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;  
    351.         }  
    352.         return ~returnValue~1;  
    353.     }   
    354.   
    355.     [DebuggerNonUserCode]  
    356.     public bool Delete(string id)  
    357.     {  
    358.         bool ~returnValue~2;  
    359.         MethodExecutionEventArgs ~laosEventArgs~8;  
    360.         try  
    361.         {  
    362.             object[] ~arguments~7 = new object[] { id };  
    363.             ~laosEventArgs~8 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~7);  
    364.             ~PostSharp~Laos~Implementation.~aspect~2.OnEntry(~laosEventArgs~8);  
    365.             if (~laosEventArgs~8.FlowBehavior == FlowBehavior.Return)  
    366.             {  
    367.                 return (bool) ~laosEventArgs~8.ReturnValue;  
    368.             }  
    369.             try  
    370.             {  
    371.                 Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Delete);  
    372.                 object[] arguments = new object[] { id };  
    373.                 MethodInvocationEventArgs eventArgs = new MethodInvocationEventArgs(delegateInstance, arguments);  
    374.                 ~PostSharp~Laos~Implementation.~aspect~5.OnInvocation(eventArgs);  
    375.                 ~returnValue~2 = (bool) eventArgs.ReturnValue;  
    376.             }  
    377.             catch (Exception ~exception~3)  
    378.             {  
    379.                 object[] ~arguments~4 = new object[] { id };  
    380.                 MethodExecutionEventArgs ~laosEventArgs~5 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~4);  
    381.                 ~laosEventArgs~5.Exception = ~exception~3;  
    382.                 ~PostSharp~Laos~Implementation.~aspect~4.OnException(~laosEventArgs~5);  
    383.                 switch (~laosEventArgs~5.FlowBehavior)  
    384.                 {  
    385.                     case FlowBehavior.Continue:  
    386.                         goto Label_0160;   
    387.   
    388.                     case FlowBehavior.Return:  
    389.                         ~returnValue~2 = (bool) ~laosEventArgs~5.ReturnValue;  
    390.                         goto Label_0160;  
    391.                 }  
    392.                 throw;  
    393.             }  
    394.         Label_0160:  
    395.             ~laosEventArgs~8.ReturnValue = ~returnValue~2;  
    396.             ~PostSharp~Laos~Implementation.~aspect~2.OnSuccess(~laosEventArgs~8);  
    397.             ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;  
    398.         }  
    399.         catch (Exception ~exception~6)  
    400.         {  
    401.             ~laosEventArgs~8.Exception = ~exception~6;  
    402.             ~PostSharp~Laos~Implementation.~aspect~2.OnException(~laosEventArgs~8);  
    403.             switch (~laosEventArgs~8.FlowBehavior)  
    404.             {  
    405.                 case FlowBehavior.Continue:  
    406.                     return ~returnValue~2;   
    407.   
    408.                 case FlowBehavior.Return:  
    409.                     return (bool) ~laosEventArgs~8.ReturnValue;  
    410.             }  
    411.             throw;  
    412.         }  
    413.         finally  
    414.         {  
    415.             ~laosEventArgs~8.ReturnValue = ~returnValue~2;  
    416.             ~PostSharp~Laos~Implementation.~aspect~2.OnExit(~laosEventArgs~8);  
    417.             ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;  
    418.         }  
    419.         return ~returnValue~2;  
    420.     }  
    421. }   
  • 使用PostSharp在.NET平台上实现AOP

    2012-08-21 11:05:14

     

    摘要

    本文首先介绍AOP(面向方面编程)的相关概念及理论,然后介绍如何使用PostSharp框架在.NET平台上实现AOP,最后对PostSharp的机制及AOP的优劣进行一个简单的分析。

    AOP(Aspect-Oriented Programming)

    AOP的基本定义及作用

    根据维基百科的定义,“AOP(Aspect-Oriented Programming)是一种将函数的辅助性功能与业务逻辑相分离的编程泛型(programming paradigm),其目的是将横切关注点(cross-cutting concerns)分离出来,使得程序具有更高的模块化特性。AOP是面向方面软件开发(Aspect-Oriented Software Development)在编码实现层面上的具体表现(面向方面软件开发AOSD是一个囊括面向方面分析、面向方面设计和面向方面编程等一系列概念的完整工程系统——笔者注)。AOP包括编程模型和具体用于实现AOP的框架两部分。”

    下面对上文提到的定义进行一些解释。

    在当前大多数支持面向对象的编程语言中(例如C#,Java等),函数(Function)是表述程序功能的最小单元,而一个函数的代码层面往往同时含有核心业务逻辑和辅助性功能。核心业务逻辑指一个函数本身主要要实现的业务功能,例如在一个在线电子商务系统中,“PlaceOrder”函数其核心业务逻辑是“下订单”,而“UpgradeMember”函数其核心业务是“提升一个会员的等级”。但是,一个函数除了核心业务代码外,往往还会有一些辅助性功能代码,如事务处理、缓存处理、日志记录、异常处理等等。而这些辅助性功能一般会存在于大多数甚至所有业务函数中,即形成AOSD中所谓的横切关注点,如图1所示。

    image

    图1、横切关注点示意

    横切关注点的存在,造成了如下几个问题。

    • 代码编写和维护困难。

    横切关注点不仅横切各个函数,还可能在不同类甚至不同工程间横切,使得同一个辅助功能(如事务处理)分散到各处,如果要增加新函数时要时刻注意别忘了添加所有需要的横切代码。另外,如果需要对其进行修改,则需要到所有被横切的函数中修改,维护难度极大。

    • 引入大量冗余代码

    由于同一个辅助性功能的代码几乎是完全相同的,这样就会令同样的代码在各个函数中出现,引入了大量冗余代码。

    • 降低代码质量

    横切关注点令核心业务代码和辅助性代码杂糅纠缠在一起,破坏了业务函数代码的纯净性和函数职责的单一性,引入了大量繁杂的代码和结构,使得代码质量下降。

    所以,AOP的核心思想就是在编写代码时将横切关注点分离出来,形成单独的模块,单独编写和维护,不再分散到各业务函数,使得业务函数仅包含核心业务代码,从而解决以上问题。而在程序编译或运行时,通过某些手段(下文介绍)令独立的横切关注点代码可以与核心业务代码自动协作运行,完成本身需要的功能。

    AOP相关术语

    方面(Aspect)

    一个Aspect指上文提到的横切关注点在编程中的具体实现,它包含一个横切关注点所需要实现的具体辅助功能。具体到代码中,Aspect可能会被实现为一个Class,一个Function或一个Attribute。

    连接点(Join Point)

    连接点指一个业务函数代码中的一个位置或时机,在这个位置或时机允许Aspect代码插入执行。常见的连接点有进入函数执行业务代码前时、执行完全部业务代码离开函数前、当有异常发生在异常处理代码执行前等等。

    织入(Weaving)

    织入指将指定的Aspect代码插入指定连接点,使得横切代码与业务代码交合在一起。

    连接模型(JPM, Join Point Model)

    JPM主要是面向方面语言(如AspectJ)或面向方面框架的语义模型。主要包含以下三点:有哪些可用连接点,如何指定连接点以及如何织入。

    AOP的实现方式

    一般来说,在纯编译型语言(如C、C++)等语言中实现AOP非常困难,必须完全从编译器角度入手。本文主要讨论托管型语言(如C#,Java)中AOP的实现方式。AOP的主要实现方式有编译时AOP和运行时AOP两种,下面分别介绍。

    编译时AOP(静态织入)

    编译时AOP的实现思想是给语言的编译器做扩展,使得在编译程序的时候编译器将相应的Aspect代码织入到业务代码的指定连接点,输出整合的结果。图2是编译时AOP的示意图(以.NET平台为例)。

    image

    图2、编译时AOP示意图

    如图2所示,当使用静态织入时,带AOP扩展的编译器会在编译时将Aspect代码织入业务函数代码,形成整合后的IL,然后交由CLR运行。

    运行时AOP(动态织入)

    运行时AOP如图3所示。image

    图3、运行时AOP的示意图

    如图3所示,运行时AOP的实现方式是将扩展添加到运行虚拟机而不是编译器。Aspect和业务代码分别独立编译,而在运行时由虚拟机在必要时进行织入。

    PostSharp

    PostSharp简介

    PostSharp是一个用于在.NET平台上实现AOP的框架,是我比较常用的一个AOP框架,官方网站为http://www.sharpcrafters.com。目前最新版本为2.0,但是2.0的license不再免费,因此个人建议下载1.5版,同时下文都是基于PostSharp1.5。

    PostSharp使用静态织入方式实现AOP,其连接点非常丰富,使用简单,而且相对其它一些.NET平台上的AOP框架来说,PostSharp较为轻量级,但是功能却一点也不逊色,因此是我比较喜欢的一个AOP框架。更多关于PostSharp的介绍请参看其官方网站。

    另外使用PostSharp与其它框架不太一样的是一定要下载安装包安装,只引用类库是不行的,因为上文说过,AOP框架需要为编译器或运行时添加扩展。

    使用PostSharp实现AOP示例

    这一节将通过一个例子演示如何使用PostSharp在.NET平台上实现AOP。这个例子将通过AOP为核心业务函数增加日志记录功能。

    新建项目

    首先新建一个C#的WinForm应用程序,如图4所示,这里将工程命名为“PostSharpExample”。

    image

    图4、新建项目

    编写核心业务函数

    首先我们来编写核心业务。当然这里不存在真正的业务,我们只是模拟一个而已。将要模拟的核心业务是预定房间。先构建一个如图5所示的简单UI。

    image

    图5、UI界面

    下面我们为项目增加一个“CoreBusiness”类,并在其中添加“Subscribe”方法。代码如下:

    using System;
    
    namespace PostSharpExample
    {
        public class CoreBusiness
        {
            public static void Describe(string memberName, string roomNumber)
            {
                System.Windows.Forms.MessageBox.Show(String.Format("尊敬的会员{0},恭喜您预定房间{1}成功!", memberName, roomNumber), "提示");
            }
        }
    }

    可以看到,这里Subscribe方法仅仅是输出一个提示框。当然,在真正项目中这种输出型代码不应该写在业务逻辑中,这里这样写主要是为了演示方便。然后,我们在Form1中调用Subscribe业务方法:

    using System;
    using System.Windows.Forms;
    
    namespace PostSharpExample
    {
        public partial class Form1 : Form. {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void BTN_SUBSCRIBE_Click(object sender, EventArgs e)
            {
                if (!String.IsNullOrEmpty(TXB_NAME.Text.Trim()) && !String.IsNullOrEmpty(TXB_ROOM.Text.Trim()))
                    CoreBusiness.Describe(TXB_NAME.Text.Trim(), TXB_ROOM.Text.Trim());
                else
                    MessageBox.Show("信息不完整","提示");
            }
        }
    }

    运行程序就可以看到相应的效果:

    image

    图6、预定房间成功演示效果

    使用AOP增加日志记录功能

    现在加入我们要为程序添加日志功能,记录业务函数的执行情况。这里我们假定需要将日志记录到纯文本文件中,首先我们完成日志记录工具类,LoggingHelper。

    using System;
    using System.IO;
    
    namespace PostSharpExample
    {
        class LoggingHelper
        {
            private const String _errLogFilePath = @"log.txt";
    
            public static void Writelog(String message)
            {
                StreamWriter sw = new StreamWriter(_errLogFilePath, true);
                String logContent = String.Format("[{0}]{1}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"), message);
                sw.WriteLine(logContent);
                sw.Flush();
                sw.Close();
            }
        }
    }

    如果不使用AOP,则我们要为包括Subscribe在内的每一个方法在核心业务代码的前后插入日志记录代码(Writelog),我们看看使用PostSharp如何将这种横切关注点分离出来。因为要使用PostSharp,所以要先添加对PostSharp库文件的引用,安装过PostSharp后,在系统可引用项中会多出“PostSharp.Laos”、“PostSharp.Public”和“PostSharp.AspNet”,这里我们做的是Winform程序,所以只需添加对“PostSharp.Laos”和“PostSharp.Public”的引用即可。

    下面我们就要写Aspect了,PostSharp的Aspect是使用Attribute实现的,下面是我实现的日志记录Aspect代码。

    using System;
    using PostSharp.Laos;
    
    namespace PostSharpExample
    {
        [Serializable]
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
        public sealed class LoggingAttribute : OnMethodBoundaryAspect
        {
            public string BusinessName { get; set; }
    
            public override void OnEntry(MethodExecutionEventArgs eventArgs)
            {
                LoggingHelper.Writelog(BusinessName + "开始执行");
            }
    
            public override void OnExit(MethodExecutionEventArgs eventArgs)
            {
                LoggingHelper.Writelog(BusinessName + "成功完成");
            }
        }
    }

    我们约定每个Aspect类的命名必须为“XXXAttribute”的形式。其中“XXX”就是这个Aspect的名字。PostSharp中提供了丰富的内置“Base Aspect”以便我们继承,其中这里我们继承“OnMethodBoundaryAspect ”,这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关,具体为什么请参看这里

    我们的LoggingAttribute非常简单,就是在进入(Entry)和离开(Exit)函数时分别记录日志到log文件。现在我们把这个Aspect应用到业务方法上:

    [Logging(BusinessName="预定房间")]
    public static void Describe(string memberName, string roomNumber)
    {
        System.Windows.Forms.MessageBox.Show(String.Format("尊敬的会员{0},恭喜您预定房间{1}成功!", memberName, roomNumber), "提示");
    }

    可以看到,应用Aspect非常简单,就是将相应的Attribute加到业务方法上面。现在我们再运行预定房间程序,结果和上次没什么两样,但是如果我们打开程序目录,会看到多了一个“log.txt”文件,里面记录有类似图7的内容。

    image

    图7、日志内容

    可以看到,我们已经通过AOP实现了日志记录功能。通过AOP将横切关注点分离出来后,日志记录的代码都放在LoggingAttribute里,需要修改只要修改一处即可。同时,业务方法仅含有业务代码,这样大大提高了程序代码的可读性和可维护性。

    对PostSharp运行机制的简要分析

    上文已经说到,PostSharp使用的是静态织入技术,下面我们分析一下PostSharp是如何实现的。

    首先,当安装PostSharp时,它自动为Visual Studio编译器添加了AOP扩展。如果仔细观察PostSharpExample编译信息,会发现有这么两行:

    image

    图8、PostSharp编译信息

    很明显,在.NET Complier编译完成后,下面PostSharp又做了一部分工作,这部分工作就是静态织入的过程。如果我们用.NET Reflector查看PostSharpExample.exe中Subscribe方法的反编译代码,会发现多了很多东西:

    image

    图9、织入Aspect后的Describe代码(由.NET Reflector反编译)

    这些多出来的代码,就是PostSharp静态织入进去的。当然,这些代码在每次编译完成后,PostSharp都会重新织入一次,所以整个过程对程序员是透明的,我们只需维护纯净的业务代码和Aspect代码即可。

    使用PostSharp的优点和缺点(即使用AOP的优点和缺点)

    总体来说,使用PostSharp,将会带来如下优点:

    • 横切关注点单独分离出来,提高了代码的清晰性和可维护性。
    • 只要在Aspect中编写辅助性功能代码,在一定程度上减少了工作量和冗余代码。

    当然,使用PostSharp也不是没有缺点,主要缺点有如下两方面:

    • 增加了调试的难度。
    • 相比于不用AOP的代码,运行效率有所降低。

    所以,对于是否引入AOP,请根据项目具体情况,权衡而定。

    对于PostSharp的进一步学习

    本文只是简要介绍了PostSharp以及实现了一个小例子,并不打算详细完整地介绍PostSharp的方方面面,而只想起到一个抛砖引玉的作用。PostSharp还有非常丰富的功能等待各位学习,因此,如果您对PostSharp十分有兴趣,想进一步学习,请参看PostSharp官方参考文档

  • bugzilla 安装

    2012-02-14 16:30:30

    bugzilla安装笔记

    今天终于把bugzilla装上去了!庆祝!呵呵

    perl的模块装了好几天,不是缺这就是缺那,现在终于搞定了!

    简单记一下安装步骤:

    一、安装Apache

             安装Apache比较简单

            1、下载源码包:http://download.chinaunix.net/down.php?id=114&ResourceID=66&site=1

            2、解包:tar -jxvf apapche-httpd-2.2.0.tar.bz2

            3、安装:cd apache-http*

                            ./configure --prefix=/usr/local/apache2 --enable-module=so

                            make      然后再      makeinstall       完成安装

            4、配置:vi /usr/local/apache2/conf/httpd.conf      添加: AddHandler cgi-script. .cgi

                                                                                             <Directory "/var/www/bugzilla/">
                                                                                                        Options All
                                                                                                        AllowOverride Limit
                                                                                                        Order allow,deny
                                                                                                        Allow from all    
                                                                                             </Directory>                                                  

    二、安装mysql

            1、下载源码包:http://download.chinaunix.net/down.php?id=24933&ResourceID=7159&site=1

            2、解包:tar -zxvf mysql-5.0.32.tar.gz

            3、安装:cd mysql-5.0*

                            ./configure --prefix=/usr/local/mysql

                            make       然后      make install      完成安装

            4、初始化mysql:/usr/local/mysql/bin/mysql_install_db --user=root

                                        /usr/local/mysql/bin/mysqld_safe --user=root &      (启动mysql服务端)

                                        /usr/local/mysql/bin/mysql --user=root      ( 启动mysql客户端)

                                        use mysql; (选择系统数据库)  

                                        update user set Password=password('YourPassword') where User='root';(设置数据库root密码)

                                        insert into user (User,Host,Password,Select_priv,Insert_priv,Update_priv,Delete_priv,Index_priv,Alter_priv,Create_priv,Drop_priv,Grant_priv,Reload_priv,Shutdown_priv,Process_priv,File_priv) values('mysql','',password('YourPassword'),'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); (增加数据库用户)

    三、安装Perl

            1、下载源码包:http://download.chinaunix.net/down.php?id=78&ResourceID=44&site=1

            2、解包:tar -jvxf perl-5.8.8.tar.bz2

            3、安装:rm -f config.sh Policy.sh

                            sh Configure -de

                            make      然后 make test      通过后再 make install

            (类似的开发工具包建议在安装系统时就装上,以后会少很多麻烦。假如这里编译出现问题,根据提示,找到相应的包装上就可以了。个人比较喜欢ubuntu的apt-get install,没这么多麻烦~)

    四、安装perl模块(这才是最烦人的地方)

            1、首先初始化perl的cpan:perl -MCPAN -e 'shell'

                  命令执行以后会进行一系列的配置,都有提示这一步是比较简单的,一般一路回车就可以了,最后会选模块搜索服务器,这个在大陆比较快(http://cpan.linuxforum.net/)把它选在前面就可以了。

                 cpan是Comprehensive Perl Archive Network的英文缩写,一个巨大的网络资源库。有了它后面安装perl的模块会相对简单一些。

            2、安装bugzilla所需的perl模块

            必要模块:    

            1. CGI 2.93 or CGI 3.11 if using mod_perl
            2. Date::Format (2.21)
            3. DBI (1.41)
            4. DBD::mysql (2.9003) if using MySQL
            5. DBD::Pg (1.45) if using PostgreSQL
            6. File::Spec (0.84)
            7. Template (2.12)
            8. Email::Send (2.00)
            9. Email::MIME::Modifier (any)

           可选模块:

            1. GD (1.20) for bug charting
            2. Template::Plugin::GD::Image (1.20) for Graphical Reports
            3. Chart::Base (1.0) for bug charting
            4. GD::Graph (any) for bug charting
            5. GD::Text (any) for bug charting
            6. XML::Twig (any) for bug import/export
            7. MIME::Parser (5.406) for bug import/export
            8. LWP::UserAgent (any) for Automatic Update Notifications
            9. PatchReader (0.9.4) for pretty HTML view of patches
           10. Image::Magick (any) for converting BMP image attachments to PNG
           11. Net::LDAP (any) for LDAP Authentication
           12. SOAP::Lite (any) for the web service interface
           13. HTML::Parser (3.40) for More HTML in Product/Group Descriptions
           14. HTML::Scrubber (any) for More HTML in Product/Group Descriptions
           15. Email::MIME::Attachment::Stripper (any) for Inbound Email
           16. Email::Reply (any) for Inbound Email
           17. mod_perl2 (1.999022) for mod_perl
           18. CGI (2.93) for mod_perl
           19. Apache::DBI (0.96) for mod_perl2

            有点汗~~我是被这些模块,折腾了几天了~~

            不过,别急~ perl提供了很简便的模块安装方式:perl -MCPAN -e 'install 模块名' 。比如安装bugzilla的模块,执行这个命令就可以了(理论上的):perl -MCPAN -e 'install "Bundle::Bugzilla"' 。不过,一般不会成功(上面个命令是将所有模块一起装,还可以将各模块分开装,比如:perl -MCPAN -e 'install GD::Graph"')。

            经过上面的步骤,应该可以装下一些perl模块了。运气好,全部都可以装上。假如您和我一样属于运气超差的那一类,那就接着下面的步骤走:

            首先分析安装失败的原因:

            失败的原因无外乎有二:一是缺少相关软件包;二是操作、配置不正确。

            排开第二项,要解决的就是第一项了。前几天之所以失败,原因就在于贪图便宜,一直用perl -MCPAN -e 'install 模块名' ,这样的方式来装,结果总是失败,尤其是GD模块,装不上,还不知道原因。perl的cpan虽然会分析安装关联,但是她只局限于自己的范围内关联,不是她范内的事,她就不管了。后来终于灵机一动,手动安装——这样可以看出出错信息,知道缺少什么,然后再去找来装上就OK了。

            手动安装,先要到网上把bugzilla所需的模块都下下来(http://download.chinaunix.net这里您要的都有,强!)然后分别解压,安装就OK了。如果中途遇到出错,根据出错提示,很容易判断出出错的原因,一般会是缺少其他的工具,去网上找下来先装她就OK了。要补充一句的是,perl模块的安装稍微有点不同。./configure换成perl Makefile.PL 后面一样了make      然后 make install

            手动安装+自动安装,不能装的都装上了。高兴,呵呵!

    五、安装sendmail或者(qmail)

              红帽sendmail默认已经可以用了,如果没有,建议安装qmail。

    六、安装bugzilla(吐口气,很简单了~)

            1、下载源码包:http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-2.22.2.tar.gz

            2、解包:tar zxvf bugzilla-2*

            3、配置:mkdir /var/www/bugzilla     

    (创建bugzilla目录)

                            cd bugzilla*         

     然后           mv * /var/www/bugzilla     

    (移动bugzilla文件到apache服务目录)

                            chmod -R 777 /var/www/bugzilla     

    (改变权限)

                            /var/www/bugzilla/checksetup.pl

    (检查安装,如果上一步的perl模块没有装好,这里会提示)

                            vi /var/www/bugzilla/localconfig

    修改以下内容:

                                               $db_host = "localhost";
                                               $db_name = "bugs";
                                               $db_user = "mysql";
                                               $db_pass = "YourPassword";

                            /var/www/bugzilla/checksetup.pl

    (自动创建数据库,设置目录权限,完了以后,要你输入bugzilla管理员的邮箱,密码等,这是登录用的,要记住。)

                           

    再来一次 /var/www/bugzilla/checksetup.pl 确认已经成功

    哈哈,赶快登录你的bugzilla吧!(第一次登录会要求你做一些配置,都有提示,按照提示做就OK啦!俺要睡觉了,晚安~~)                                                 

        


    http://hi.baidu.com/windinthewillows/blog/item/51c01c82c78f13a30df4d24b.html
  • ruby 安装

    2011-09-28 12:58:03

    编写背景:
    有半年多没有写
    Ruby+Waitr的自动化测试脚本了,今天开始封网测试机器会被关闭,赶着这段国庆空闲时间,好好整整开源的自动化测试工具,争取淮海战役打完后,组织测试组的帅哥美女们开始写些自动化测试代码,为明年的测试工作效率提升打基础。
    好久没装,今天费了一上午终于给装上了,这次要好好整理出文档才行,便于下次使用时可查阅,同时共享给对这方面感兴趣的测试同行。
    一、工具介绍:
    Ruby Ruby是面向对象的编程语言,它追求的是[font=ˎ̥]简便快捷的面向对象编程[font=ˎ̥]Ruby是解释型语言,因此不需编译即可快捷地编程。同时Ruby具有类似Perl的强大的文本处理功能,它可并不只是个玩具,您可以用它来进行实用的编程。此外,您还可以很方便地使用[font=ˎ̥]C语言来扩展Ruby的功能,因此可以把她当作各种库的前端来使用。
    Watir Watir( Web Application Testing in Ruby) 是一个优秀的开源工具,用于开发基于Web 应用的自动化测试程序。它使用Ruby 脚本语言,提供了轻量级的自动化测试程序框架和丰富的开发库,有效地加速了自动化测试程序开发。
    Watir 的主要特性以及使用 Watir 开发自动化程序的优势
    Watir是一个轻量级的用于开发基于Web应用的自动化测试框架,它基于Ruby语言,提供了丰富的开发库,简化了自动化测试程序开发。下面我们总结了Watir的主要一些优良特性:
    l         [font=ˎ̥]Watir 基于[font=ˎ̥] Ruby 语言。[font=ˎ̥] Ruby 是面向对象语言,功能强大,简单易用。程序解释执行不用编译;
    l         [font=ˎ̥]Watir 支持多种操作系统平台,包括[font=ˎ̥] Windows, Mac, Linux ;同时支持多种主流浏览器,如[font=ˎ̥] IE, Firefox, Chrome
    l         [font=ˎ̥]Watir 提供了丰富的开发库,封装了包括浏览器窗口[font=ˎ̥] windows[font=ˎ̥]button, link, dialog, image, table, div 等绝大多数[font=ˎ̥] HTML 对象类型,方便测试人员快速构建自动化测试程序。
    l         [font=ˎ̥]Ruby 提供了强大的交互命令工具[font=ˎ̥] IRB[font=ˎ̥]Interactive Ruby Shell[font=ˎ̥], [font=ˎ̥] Watir 程序开发中,我们使用[font=ˎ̥] IRB 调试代码。别于传统调试方法,测试人员可以就单独一条命令或者一段程序进行调试,从而能够快速定位错误,节省调试时间。
    l         [font=ˎ̥]Ruby 提供了[font=ˎ̥] Test::Unit 单元测试框架,通过继承该框架,我们可以对测试用例,测试用例集[font=ˎ̥] (Test Suites) 进行灵活方便地组合和调用,并且可利用断言[font=ˎ̥] (Assertion) 来验证测试结果。
    l         其他脚本语言如[font=ˎ̥] Perl, Python, Shell 等也可以很好地集成到[font=ˎ̥] Watir 程序中。
    l         [font=ˎ̥]Watir 程序在运行时,允许测试人员在该测试机器上访问其他网页或者进行其他操作而不会影响到对象识别的结果。
    二、开源自动化测试工具组合:Ruby+Watir安装
    安装准备:
    1.       工具安装包准备:
    Ruby官方下载地址:http://www.ruby-lang.org/zh_cn/downloads/,稳定版本Ruby 1.8.6
    Watir下载地址:http://rubyforge.org/frs/?group_id=104&release_id=28016,建议装watir 1.5.2
    Firefox下载地址:http://www.hacker.cn/Get/gjrj/06102608545293311.shtml,建议装2.0
    Gem下载地址:http://rubyforge.org/frs/?group_id=104&release_id=28016
    建议装:rubygems-update-1.3.4.gem

    Firefox插件jsshfirebugfirewatir下载
    Jssh下载地址:用Google搜索,之前找的忘记是那了,建议装jssh-WINNT-2[1].x.xpi
    Firebug下载地址:用google搜索,之前找的忘记是那了,建议装firebug-1.05
    Firewatir下载地址:http://code.google.com/p/firewatir/downloads/list,建议装firewatir-1.1
    2.       安装步骤:
    Ø         安装环境:Windows xp
    Ø         安装ruby,直接点击rubyexe安装文件即可
    Ø         安装firefox,直接点击exe安装文件即可
    Ø         安装firefox插件,安装方法:打开firefox浏览器,点击“文件”/“打开”,选择插件文件名,安装即可;提醒:需要安装插件有:jsshfirebug
    Ø         安装firewatir,安装方法:点击“开始”/“运行”,在页面输入命令:cmd,进入DOS命令操作界面;进入ruby安装的目录,输入命令:gem install firewatir-1.1.gem
    Ø         安装watir
    1)      点击“开始”/“运行”,在页面输入命令:cmd,进入DOS命令操作界面,
    2)      进入ruby安装的目录,输ruby –v,查看ruby版本,显示:Ruby 1.8.6
    3)      输入gem –v,查看gem版本,显示0.94
    4)      升级gem,把gem包拷贝到ruby安装目录,在dos界面输入命令:gem install rubygems-update-1.3.4.gemgem包名)

    提醒:安装完后进入ruby目录:libuby\gems\1.8\gemsubygems-update-1.3.4,点击这个文件夹中的文件:setup.rb,升级gem即可

    5)      安装watir包,把watir包拷贝到ruby安装目录,在dos界面输入命令:gem install watir-1.5.2.gem
    3.       安装完毕检查
    dos界面,进入firewatir安装路径下(一般在:"ruby"lib"ruby"gems"1.8"gems"firewatir-1.1),进入unittests文件夹,输入命令:ruby mozilla_all_tests.rb,如果可以正确执行程序,说明安装正确没有问题,到此可以开始自动化测试开发的旅程了。^_^

  • [转] 如何学习自动化测试工具QTP

    2009-05-11 10:23:03

      网上看到一篇写的不错的文章,个人觉得总结的比较全面,转载过来分享下。-_-

        本文出自:http://www.51testing.com/?161787

        从事了几年测试工作,也着实见证了测试的发展,如今测试行业对从业者的要求是越来越高,不再仅仅局限于要求会写测试用例、会细致的执行测试、能有效的发现系统缺陷等;越来越多的企业对应聘者本身的技能要求也越来越高,招聘信息中诸如“精通VBscrīpt、Perl/Rbuy等至少一门脚本语言”、“至少熟悉一门开发语言”、“精通QTP、LR等自动化测试工具”、“有大型项目自动化实施成功经验”此类的字眼也逐渐增多。目前看来,除白盒测试内容和测试管理外,主流的方向有两个:功能自动化测试和性能测试。这就要求从业人员能够在短时间内快速的掌握这些知识,才能获取到更好的工作机会。本人是名功能自动化测试的工程师,以自己学习、工作的过程结合QTP讲讲该如何学习自动化测试

        首先,想从事自动化测试,必须先了解What/Why/How,也就是常说的去了解什么是自动化测试、为什么要进行自动化测试、该如何进行自动化测试,这类的资料在网上有很多,这里就不做重复了

    其次,需要根据项目的特点,选择合适的自动化测试工具,并了解工具的特性。以QTP为例,该如何去掌握它呢?对于初学者,大多数都是通过录制的方式来生成脚本,这个阶段应该掌握的基础知识有

         1)   QTP是如何去识别对象的,对于新手经常会出现录制的脚本回放的时候报错的现象,这个时候就应该考虑为什么呢?如果很了解QTP识别对象的原理啊,我想就能很快定位到原因了

         2)   去掌握一些QTP对象的方法,如GetROPreperty、GetTOPreperty、ChildObjects等等,对于相似的方法应该去搞清楚到底区别在哪?像GetROPreperty、GetTOPreperty有什么区别等

         3)   什么是Action参数、什么又是Test参数?两者有什么区别,又有什么联系,在同一Test和不同Test间这些参数如何工作

         4)   什么是环境变量?环境变量是如何建立和使用的,环境变量在参数传递中和action参数、test参数有什么不同

         5)   了解检查点的知识,明白什么是内置检查点,什么又是自定义检查点。并搞清楚在什么时候该如何使用检查点

         6)   掌握对象库的操作,了解对象库对于测试的意义,象是否启用智能识别对测试脚本有何影响、为什么同一对象识别起来会有_1、_2之类的后缀等都是需要去研究清楚的问题

        这几个问题都搞清楚的话,那基本就能够利用QTP生成正确的脚本了,当然以上只是部分必须掌握的内容,其实还是很多细节的设置,就需要在实际运用中去掌握了。

        接下来,就可以进一步提升自己的QTP运用水平了,这个阶段就需要去学习vbs知识和如何运用描述性编程实现脚本了,同时在这个过程中还需要去学习html知识、DOM、XML、以及像excel、word等的API知识了,总的来说,这个阶段应该掌握的内容大体上包括

         1)   VBscrīpt的基础知识,熟悉常用的方法和函数,掌握文件对象的操作等

         2)   熟练掌握XML技术;excel、word等API对象,可以根据需要创建日志等

         3)   熟练掌握DOM和HTML知识,能够结合这些技术对Web页面进行解析

         4)   掌握数据库的基本操作语句,能够利用ADO对象进行数据操纵

         5)   熟练掌握正则表达式,很多时候处理对象问题相当方便

         6)   掌握如何调用dll进行工作

         7)   能够利用QTP的自动化对象模型创建出需要的运行模式

         8)   掌握WMI知识

        以上只是我考虑到的部分,并不全面,呵呵,供大家参考,当然这些技术主要是针对Web系统运行,因为我们的系统就是B/S的,呵呵。如果这些知识都能够扎实的掌握的话,个人认为,基本上能够处理自动化过程中的绝大多数问题了,这个时候你对自动化测试的技术应该是有一定积累了

    接下来就需要考虑自动化测试框架问题了。当脚本规模到了一定的程度,就会面临一些问题,如:

         1)   如何有效的管理并调度脚本

         2)   如何实现脚本运行的无人值守,测试过程中能够自动进行错误处理并进行日志记录

         3)   如何生成简介明确的测试报告

         4)   如何能够更加高效的维护测试脚本

         5)   实现框架代码和业务代码的分层、业务脚本和业务数据的分离

        这个阶段主要体现的是测试人员的测试思想,是可以脱离工具独立存在的过程。当然各个公司项目的实际情况不同,导致设计出来的思想不同,但总体上来说一般包括数据驱动和关键字驱动两种模式。后者实现的技术难度大于前者,大多数公司目前都采用的数据驱动模式。这个阶段不应局限于技术运用上,而需要从测试全局考虑,进行分层设计、模块化实现,减少代码之间的耦合

    如果以上三个方面都能够做的很好的话,那么恭喜你,你已经可以独立负责项目的自动化测试建立工作了,呵呵!

        总之,学习自动化测试需要在实际项目中进行,这样提高的会比较快,项目中运用了很多种技术,自动化实施过程会碰见各种各样的问题,是很好的学习机会,关键要善于总结、积累经验,只要能够把各个细节做好,那么你一定能够成为一名优秀的自动化测试工程师

  • LoadRunner 如何选择合适的协议

    2008-10-16 16:52:40

    LR的录制工作原理,LR跟WR不一样,它不关心你的对象识别什么,不关心你的什么窗口之类的,LR有一个Agent的进程,来专门监控客户端与服务器之间的通信,然后用自己的函数进行录制,所以说,LR录制的时候关心的是通信,是客户端与服务器之间的数据包。说到这里,大家就比较清楚了,为什么有的时候不能录制呢?因为,协议不认识阿,导致LR截获的数据包不能解析,所以录制下来是空的。

    到这里看来,我们怎么样选择协议呢?当然原则就是说,你的数据包的通信协议能被LR 识别。

    过去流行的一种看法是,只要B/S结构的都是选择http协议,如果不是B/S 结构的那肯定是socket, 其实这种说法比较片面,我觉得要真正理解这个问题,必须搞杏出你所测系统的数据流采用什么协议包装的,这个我个人觉得,最好是能去向开发人员多理解这个问题,多学习。

    协议参考选择:

    应用类型   协议选择

    1,web 网站  Http/HTML

    2, FTP 服务器 FTP

    3, 邮件服务器 IMAP, POP3, SMTP

    4, C/S (第一种)客户端 以ADO, OLEDB方法连接后台数据库 MSSQL Server, Oracle, Sybase, DB2, Infirmix

        C/S (第二种) 客户端以ODBC方法廉洁后台数据库 ODBC

       C/S (第三种) 没有后台数据库 Socket

    5, ERP系统 SAP Peoplesoft

    6, 分布式组件  COM/DACOM EJB

    7, 无线应用 WAPPALM

    总之,只有充分理解被被测系统的应用类型和技术架构,才能做出正确的选择。

     

    以上内容为摘抄,觉得写的不错,就摘下来自己收藏。

     

Open Toolbar