[小北De编程手记] : Lesson 08 - Selenium For C# 之 PageFactory & 团队构建

  本文想跟大家分享的是Selenium对PageObject模式的支持和自动化测试团队的构建。《Selenium For C#》系列的文章写到这里已经接近尾声了,如果之前的文章你是一篇篇的读下来并动手实践的话,我相信你应该可以模拟日常工作中80%常见的手动测试用例了。请注意:我的用词是模拟用例,而不是书写自动化测试用例。一个企业级的自动化测试的构建不是单靠Selenium一种技术就能Hold住的。所谓模拟指的是只能实现自动化的某个Case,但是不能工程化的使用。在本人所接触过几家公司的自动化测试的实践中,有很多没有或着不是很合理分层和封装的自动化测试框架。Test Case中操作页面驱动的Code随处看见,无法根据人员的技术能力来分工,无法切换测试环境,只能使用单一的浏览器测试,对QA的使用门槛要求较高… …等等问题。

本文将会介绍如下内容:

  • PageObject设计模式介绍。
  • Selenium对PageObject模式的支持。
  • 简单的测试结构
  • 自动化测试Team成员分工
  • Demo:博客园个人首页的实现(这个是骗你的... ...)

(一)PageObject设计模式介绍

   Page Object是业界比较流行的自动化测试设计模式,能够有效的提高自动化测试的可维护性和代码的复用率。几乎所有的自动化测试驱动框架都提供了对该模式的支持(Appium ,QTP ,White等)。当然,即使你使用的驱动不支持,我们也完全可以编写代码来实现它。毕竟所谓设计模式不过代码的组织和协作方式而已。

  什么是Page Object模式呢?简单的说,就是把待测试应用程序的页面封装成一个对象,暴露相关的属性和方法给使用者(具体测试用例的编写人员)。下图是针对页面的封装:

  可以看到,Page类提供了一个TitleText属性向用户返回页面的Title文本,还提供基本的页面操作。对于使用者来说,他们不必关心这个页 面上的元素是如何定位,也不必关心内部使用了怎样的技术实现(Selenium,还是QTP)。另一个好处就是如果开发对页面做了元素做了一定的调 整,我们只需要处理PageObject内部的代码实现,而不需要修改实际测试用例代码。该模式的好处还有很多,本文就不赘述了。我会在之后的框架实践相关的文章中进行描述。

(二)Selenium对PageObject模式的支持

  下面我们一起来看一下,Selenium 对PageObject模式的支持。下面的代码是一个登录页面的简单封装:

 1     public class SignInPage
 2     {
 3         public IWebDriver Driver { get; set; }
 4         public DashboardSignInPage(IWebDriver driver)
 5         {
 6             this.Driver = driver;
 7             PageFactory.InitElements(driver, this);
 8         }
 9         #region Page elements
10         [FindsBy(How = How.Id, Using = "username")]
11         protected IWebElement txtUserName;
12 
13         [FindsBy(How = How.Id, Using = "password")]
14         protected IWebElement txtPassword;
15 
16         [FindsBy(How = How.XPath, Using = ".//button[text()='Sign in']")]
17         protected IWebElement btnSignIn;
18         #endregion Page elements
19 
20         #region Action for test case
21         /// <summary>
22         /// Sign In for Dashboard
23         /// </summary>
24         /// <param name="userName">User name</param>
25         /// <param name="password">Password</param>
26         public void SignIn(string userName, string password)
27         {
28             this.txtUserName.Clear();
29             this.txtPassword.Clear();
30 
31             this.txtUserName.SendKeys(userName);
32             this.txtPassword.SendKeys(password);
33 
34             this.btnSignIn.Click();
35         }
36 
37         //Other action... ...
38         #endregion
39     }        

  上面的代码中出现的FindsBy和PageFactory正是Selenium WebDriver提供的针对PageObject模式的支持。

  @PageFactory类

  FageFactory提供了PageObject实例的能力,我们可以看到它本身提供了很多的方法来构建具体的页面类的实例。它的主要作用的是将我们用FindsBy属性标记的字段和指定的DOM元素进行映射。而后我们可以直接使用具体属性操作DOM元素,不必使用FindElement方法来定位。

1     public sealed class PageFactory
2     {
3         public static T InitElements<T>(IElementLocator locator);
4         public static T InitElements<T>(IWebDriver driver);
5         public static void InitElements(ISearchContext driver, object page);
6         public static void InitElements(object page, IElementLocator locator);
7         public static void InitElements(ISearchContext driver, object page, IPageObjectMemberDecorator decorator);
8         public static void InitElements(object page, IElementLocator locator, IPageObjectMemberDecorator decorator);
9     }

  @FindsBy属性

  FindsBy属性是用来标记程序中的元素是如何定位的。我们可以使用之前《Lesson 03 - Selenium For C# 之 元素定位》中讲到的任何一种定位方式来标记如何定位元素。利用How参数指定定位方式,这是Using参数标识具体的值。如果对如何定位元素不是很清楚,可以查看之前的文章,这里就不再赘述了。

 1     // Summary:
 2     //     Provides the lookup methods for the FindsBy attribute (for using in PageObjects)
 3     public enum How
 4     {
 5         // Summary:
 6         //     Finds by OpenQA.Selenium.By.Id(System.String)
 7         Id = 0,
 8         //
 9         // Summary:
10         //     Finds by OpenQA.Selenium.By.Name(System.String)
11         Name = 1,
12         //
13         // Summary:
14         //     Finds by OpenQA.Selenium.By.TagName(System.String)
15         TagName = 2,
16         //
17         // Summary:
18         //     Finds by OpenQA.Selenium.By.ClassName(System.String)
19         ClassName = 3,
20         //
21         // Summary:
22         //     Finds by OpenQA.Selenium.By.CssSelector(System.String)
23         CssSelector = 4,
24         //
25         // Summary:
26         //     Finds by OpenQA.Selenium.By.LinkText(System.String)
27         LinkText = 5,
28         //
29         // Summary:
30         //     Finds by OpenQA.Selenium.By.PartialLinkText(System.String)
31         PartialLinkText = 6,
32         //
33         // Summary:
34         //     Finds by OpenQA.Selenium.By.XPath(System.String)
35         XPath = 7,
36         //
37         // Summary:
38         //     Finds by a custom OpenQA.Selenium.By implementation.
39         Custom = 8,
40     }

   那么最后,我们来看一下消费者(上层的测试用例编写人员)将如何使用如何使用这个类,这个Code只是一个使用SignInPage的示例,我们看到这里还是在测试用例中写入了创建Driver和导航页面的代码,按照先前的架构这样也是存在问题的,这里就不再展开了,期待我后续关于自动化框架设计的文章吧~~~:

 1         private const string cst_DisplayName = "BaseCheck.SignIn";
 2         [Fact(DisplayName = cst_DisplayName + ".Success")]
 3         public void SignIn_Success()
 4         {
 5             var driver = new FrieFoxDriver();
 6             driver.Url = "www.xxx.com/signin";
 7 
 8             var signInPage = new SignInPage(driver);
 9             signInPage.SignIn("your name", "password");
10 
11             //省略Code... ...    
12             driver.Close();
13         }

(三)简单的测试结构

  读到这里,即使你是初学者。想必也能明白一些PageObject设计模式为何物,这里我还是描述一下 PageObject的意图:PageObject模式是为了封装页面元素定位,页面等待、跳转等操作页面相关的逻辑。使得使用者在不必关心这些逻辑的情 况下,可以书写相关的测试用例。我们回顾一下我之前在《Lesson 02 - Selenium For C# 之 核心对象》中提到的一般的企业级测试框架中的结构图:

   上图中的红线圈出来的部分就是PageObject的消费者(编写测试用例的Tester)。可以看到,下一层的开发人员可以把页面的封装成 PageObject,上层的使用者不必关心具体的实现技术是哪一种(Selenium , Appium... ...)。PageObject的消费者可以专注于Test Case的逻辑实现。

(四)自动化测试Team成员分工

  之前有很多公司或是朋友跟我探讨过如何组建自动化测试团队。无一例外都谈到了(纠结于)这些问题:需要QA Team有很强的编码能力,他们要学习各种驱动(Selenium , QTP , Appium... ...)的使用 , 了解一些JavaScript、HTML、CSS相关的知识,具有OOP思维... ...等等等。最终的结论就是构建自动化测试对QA的人员提出了很高的要求。在我看来,如果一个QA可以具有了上述能力我想他已经是一个开发人员了(这个要求不切实际)。那可不可以让开发团队来完成这件事情呢?这个当然不行了,理由有N多。这里我只提两条。第一,开发团队的视角往往不是站在用户角度的,因此会极大的提升项目风险。第二,一个自动化测试构建的成功与否?合理的测试计划往往是决定性因素,但是测试计划的制定却不是开发人员所擅长的。(这里没有歧视开发的意思。嘻嘻~~本人也是开发~~~不喜勿喷)。那么,如何构建呢?这个其实也是我们要构建测试框架,分层,使用PageObject模式的原因了,针对上一节我画出的简单结构而言,团队中可以有如下几个角色:

@功能测试人员:

  主要是由手工测试人员和懂一些简单编程语法的测试人员组成,他们是PageObject和测试框架的直接使用者(消费者)。使用已经完成的PageObject和测试框架进行测试用例的编写,以及测试计划的制定。以我个人的经验,一般的QA简单的培训一下即可以胜任这样的工作,而他们所完成的却是很大的一部份工作。功能测试人员专注与逻辑的测试,而不易关心技术细节。

@PageObject编写人员:

  这部分人员可以由测试团队中技术(编程技术)较高或是开发人员来担当,要求如下:

  • 熟悉相关的驱动的使用(Selenium、QTP... ....),不熟悉也没关系,看看我的《Selenium For C#》系列哈~~~
  • 熟悉Web编程,JavaScript、HTML、CSS相关的知识。(基于B/S的测试构建,要是桌面或是手机端还要其他的知识)
  • 熟悉OOP思想,能针对页面做出合理的封装。

  因此,这部分同学专注与提供好用的页面类,而不必须关系纷繁复杂的业务逻辑。这部分人也是测试人员的一个职业发展方向(技术型测试)。

@测试架构师:

  这个就需要资深一些的同学来做了,架构师的要求嘛就比较多了。他在团队中主要的任务就是构建测试的基础设施。比如页面导航的管理,提供ORM机制供测试人员使用,日志的输出,测试报告的生成,环境切换,浏览器切换,提供一些炫酷而简单的使用功能,还有就是最一些文档的输出。这样一来,测试架构师也可以关心他所需要完成的技术难题,而不关心业务和具体的页面类的实现。

 

  总结一下,有了这三种分工其实工作在不同的层面上。各自完成所擅长的那一部分。于此同时也提供生了整个测试的可维护性。比如:页面做了修改,只需要PageObject人员去修改自己的封装。而业务逻辑出现了变更(页面不变的话),也只是需要用例编写人员修改一下自己的测试用了而已。

(五)写在最后的... ...

  本来是想做一个Demo给大家的。但是... ...过年了... ... 老妈催着回家过年,收拾行李去呀,有机会再补上吧 ... ... 今天就任性一把 哈哈 , 各位小伙伴,新年快乐!

  前面讲了分工,现在的你是哪个级别呢?能一篇篇把我的系列文章看到这一篇的,估计多数还是没有构建测试框架能力的小伙伴。所以,后面如果时间允许的话我会写一个关于自动化测试框架构建的系列,记得关注哦~~~

《Selenium For C#》的相关文章:Click here.

说明:Demo地址:https://github.com/DemoCnblogs/Selenium

 

如果您认为这篇文章还不错或者有所收获,可以点击右下角的【推荐】按钮,因为你的支持是我继续写作,分享的最大动力!
作者:小北@North
来源:http://www.cnblogs.com/NorthAlan
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。
posted @ 2016-02-04 17:52  小北@Alan  阅读(3426)  评论(4编辑  收藏  举报