[小北De编程手记] [Lesson 02] AutoFramework构建 之 Page Objects - 设计模式

写在最前面

  这个系列的主旨是要跟你们分享一下关于自动化测试框架的构建的一些心得。这几年,作了一些自动化测试框架以及团队的构建的工做。过程当中遇到了不少这样的同窗,他们在学习了某一门语言和一些自动化测试的类库或者工具以后,打算进一步的提升。我想这个系列也许会帮助到你,咱们一块儿从各个维度来看一看自动化测试框架的一些最佳实践。本人能力有限,若是有什么不正确的的地方还各位大牛指正。html

自动化测试 - 设计模式

    设计模式(Design pattern)表明了最佳的实践,是针对一些特定场景下问题的解决方案。设计模式是软件开发人员在软件开发过程当中面临的通常问题的解决方案。这些解决方案是众多软件开发人员通过至关长的一段时间的试验和错误总结出来的。这是网络上比较通用的对设计模式的解释。git

那么,对于自动化测试架构来讲又有哪些最佳实践呢?github

  • 领域驱动设计(Domain Driven Design):用接近终端用户的语言来表达你的测试。
  • 页面对象(Page Objects):基于UI的简单抽象。
  • 组件化(Loadable Component):组件化项目中的待测试元素。
  • 基于命令的测试(Bot Style Tests):基于命令而不是对象的设计,对Page Objects的补充
  • 验收测试(Acceptance Tests):使用粗粒度的UI测试来帮助结构开发工做。
  • 回归测试(Regression Tests):将多个验收测试的操做收集到一个地方以方便维护。

注意:这里的“验收测试”和“回归测试”是指对自动化测试用例的组织方式,而不是一般意义上的测试过程。虽然这也会成为实际测试活动的一部分。编程

    这个系列重要内容之一,就是为你们一一讲解上面的模式。 所以,这一个小节我会放在以后全部关于自动化设计模式问文章开头,由于他真的很重要~~~ 关于上述模式的总结,你在也能够在Selenium项目的Wiki里找到,连接以下: https://github.com/SeleniumHQ/selenium/wiki/Design-Patternsjson

PageObject模式目的

    这一篇,咱们要讨论的是上述模式中最有名,也是最被误用最多的模式:Page Objects。简而言之,Page Objects是咱们针对页面以及页面相关服务的封装。对于使用者来讲,每个封装好的页面对象都为他们提供了获取页面数据和页面相关的操做方法。让使用者能够简单的像手工操做同样的来书写自动化测试的用例。设计模式

咱们来回顾一下上一讲中的那个例子:网络

 1 namespace AutoFramework.TestCase
 2 {
 3     public class TestSuite_Demo : TestBase
 4     {
 5         public TestSuite_Demo(TestContextFixture context, ServiceFixture service, DBFixture database) 
 6         : base(context, service, database) { }
 7 
 8         [Fact(DisplayName = "TestCase.Demo001")]
 9         public void Demo_Case_Create()
10         {
11             //-->Data preparation.
12             var userModel = ModelBuilder.ForJsonFile<UserModel>("DemoCase/TestData.json");
13 
14             //-->Test case exec way 01.
15             var signInPage = Router.GoTo<SignInPage>();
16             var homePage = signInPage.SignIn("user-name", "pwd");
17             var addUserPage = homePage.NavMenu.Select<AddUserPage>("User", "New");
18             var userListPage = addUserPage.AddUser(userModel);
19             
20             //-->Test case exec way 02.
21             /*You can custom this 'Workflow'*/
22             var userListPage = Router.GoTo<SignInPage>()
23                 .SignIn("user-name", "pwd")
24                 .NavMenu.Select<AddUserPage>("User", "New")
25                 .AddUser(userModel);
26             
27             Assert.True(userListPage.IsExistUser(userModel.Name));
28         }
29     }
30 }

    其中,signInPage,homePage,addUserPage,userListPage 都是一些页面对象。对于书写Test Case 的人而言,他们能够不须要过多的关心页面上的实现细节。而是,更加关注业务自己。这也是框架设计的目的之一:分层架构

    自动化测试目的主要是模拟手工操做,而不少测试框架好比Selenium,Appnium,white... ...等都提供了基本的驱动支持。在实际自动化构建测试构建过程当中,UI改变致使的测试用例运行失败应该是自动化须要解决的首要问题,而PageObjects的好处之一,就是能够较好应对UI的改变对测试用维护成本的影响。框架

PageObject模式原则

上一个小节,咱们看到了如何使用封装好的PageObject对象。那么,应该如何来设计(封装)一个PageObject呢?下面列出了一个些PageObject设计的原则:工具

  • 提供公共方法来表示页面提供的服务
  • 尽可能不要暴露页面的内部细节
  • 通常不要在Page Objects中使用断言(CheckPoint),由于检查点每每是测试用例应当关心的。
  • 提供页面操做的方法返回其余PageObjects
  • Page Objects不须要完整的表达整个页面,也能够是一个组件。
  • 相同操做的若是结果不一样,应当建立不一样的方法。

仍是以登陆页面为例:

 1 public class SignInPage : PageObjectBase
 2 {
 3     public SignInPage(IWebDriver driver) : base(driver)
 4     {
 5         WaitSelector.WaitingFor_ElementExists(this.Driver,By.Id("ContentPlaceHolder1_txtUsername"));
 6 
 7         txtUserName = new TextBox(driver, By.Id("txtUsername"));
 8         txtPassword = new TextBox(driver, By.Id("txtPassword"));
 9         btnSignIn = new Button(driver, By.XPath(".//input[@value='Sign In']"));
10     }
11     
12     #region Page elements     
13     protected TextBox txtUserName;
14     protected TextBox txtPassword;
15     protected Button btnSignIn;
16     #endregion Page elements
17 
18     #region Action for test case
19     /// <summary>
20     /// Sign In
21     /// </summary>
22     /// <param name="userName">User name</param>
23     /// <param name="password">Password</param>
24     public HomePage SignIn(string userName, string password)
25     {
26         this.txtUserName.Clear();
27         this.txtPassword.Clear();
28 
29         this.txtUserName.SendKeys(userName);
30         this.txtPassword.SendKeys(password);
31         this.btnSignIn.Click();
32 
33         return new HomePage(this.Driver);
34     }
35     
36     public SignInPage SignInError(string userName, string password)
37     {
38         this.txtUserName.Clear();
39         this.txtPassword.Clear();
40 
41         this.txtUserName.SendKeys(userName);
42         this.txtPassword.SendKeys(password);
43         this.btnSignIn.Click();
44 
45         return new this(this.Driver);
46     }
47     #endregion
48 }

    能够看到,对于登陆页面的实现。基本的页面操做(好比登陆),若是行为是不一样的建议提供两个不一样的方法。登陆成功返回的是HomePage。可是若是失败了返回的是当前页面。这样的编码方式既清晰,也同时知足了前面例子中的链式调用的简洁。

    在方法的内部,咱们须要处理页面的等待延时处理,元素查找等一系列与UI相关的操做。所谓Page Objects的封装,就是但愿使用Page Objects的人不须要关心页面上的细节。

关于检查点,不少实现是在Page Objects内部提供了一些方法来检查,例如:

1 public SignInPage CheckErrorMessage(string message)
2 {
3     //... ...
4     Assert.True(message,"xxxx");
5 
6     return new this(this.Driver);
7 }

    咱们来思考一下,断言检查也就是检查Check Point应该由是测试用例自己负责,仍是由提供页面服务的Page Objects来负责呢?很明显咱们不该该在Page Objects内部处理测试用例的检查点。下面的这种处理方式是Page Objects模式自己建议的更好的作法:

让咱们如下面的这个UI为例:

 1 public string GetErrorMessage()
 2 {
 3     //返回页面上的错误信息
 4 }
 5 
 6 //调用代码
 7 ...
 8 var signInPage = Router.GoTo<SignInPage>();
 9 var errorMsg = signInPage.SignIn("user-name", "pwd").GetErrorMessage();
10 Assert.Equal(errorMsg,"用户名密码错误!");

设计模式的使用都有它的场景的意图。Page Objects模式的设计意图主要就是为了解决一下几个问题:

  • 重用操做
  • 使得自动化测试用例的编写不用关心过多的UI相关的细节
  • 应对UI的变化

    细心的同窗也许已经注意到了,UI的操做咱们并无直接是用Selenium的WebElement,而是作了一些封装。使用了相似Button,TextBox 这样的对象。这一部分涉及到的是咱们后面要讲到的另外一个设计模式Loadable Component 和 Bot Style Tests, 后面的课程会对这个专门进行讲解。

这一篇就先到这里啦~~,自动化测试框架的构建是须要必定知识基础和自动化测试经验的。但愿咱们能在接下来的这段时间里一块儿提升,希望个人观点对你有所帮助~~~

小北De系列文章:

  《[小北De编程手记] : Selenium For C# 教程

  《[小北De编程手记]:玩转 xUnit.Net》(未完成)

若是您认为这篇文章还不错或者有所收获,能够点击右下角的 【推荐】按钮,由于你的支持是我继续写做,分享的最大动力!
做者:小北@North
来源:http://www.cnblogs.com/NorthAlan
声明:本博客原创文字只表明本人工做中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未受权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文链接。
相关文章
相关标签/搜索