[小北De编程手记] [Lesson 02] AutoFramework构建 之 Page Objects - 设计模式
写在最前面
这个系列的主旨是要跟大家分享一下关于自动化测试框架的构建的一些心得。这几年,做了一些自动化测试框架以及团队的构建的工作。过程中遇到了很多这样的同学,他们在学习了某一门语言和一些自动化测试的类库或者工具之后,打算进一步的提高。我想这个系列也许会帮助到你,我们一起从各个维度来看一看自动化测试框架的一些最佳实践。本人能力有限,如果有什么不正确的的地方还各位大牛指正。
自动化测试 - 设计模式
设计模式(Design pattern)代表了最佳的实践,是针对一些特定场景下问题的解决方案。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。这是网络上比较通用的对设计模式的解释。
那么,对于自动化测试架构来说又有哪些最佳实践呢?
- 领域驱动设计(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-Patterns
PageObject模式目的
这一篇,我们要讨论的是上述模式中最有名,也是最被误用最多的模式:Page Objects。简而言之,Page Objects是我们针对页面以及页面相关服务的封装。对于使用者来说,每一个封装好的页面对象都为他们提供了获取页面数据和页面相关的操作方法。让使用者可以简单的像手工操作一样的来书写自动化测试的用例。
我们来回顾一下上一讲中的那个例子:
- namespace AutoFramework.TestCase
- {
- public class TestSuite_Demo : TestBase
- {
- public TestSuite_Demo(TestContextFixture context, ServiceFixture service, DBFixture database)
- : base(context, service, database) { }
- [Fact(DisplayName = "TestCase.Demo001")]
- public void Demo_Case_Create()
- {
- //-->Data preparation.
- var userModel = ModelBuilder.ForJsonFile<UserModel>("DemoCase/TestData.json");
- //-->Test case exec way 01.
- var signInPage = Router.GoTo<SignInPage>();
- var homePage = signInPage.SignIn("user-name", "pwd");
- var addUserPage = homePage.NavMenu.Select<AddUserPage>("User", "New");
- var userListPage = addUserPage.AddUser(userModel);
- //-->Test case exec way 02.
- /*You can custom this 'Workflow'*/
- var userListPage = Router.GoTo<SignInPage>()
- .SignIn("user-name", "pwd")
- .NavMenu.Select<AddUserPage>("User", "New")
- .AddUser(userModel);
- Assert.True(userListPage.IsExistUser(userModel.Name));
- }
- }
- }
其中,signInPage,homePage,addUserPage,userListPage 都是一些页面对象。对于书写Test Case 的人而言,他们可以不需要过多的关心页面上的实现细节。而是,更加关注业务本身。这也是框架设计的目的之一:分层
自动化测试目的主要是模拟手工操作,而很多测试框架比如Selenium,Appnium,white... ...等都提供了基本的驱动支持。在实际自动化构建测试构建过程中,UI改变导致的测试用例运行失败应该是自动化需要解决的首要问题,而PageObjects的好处之一,就是可以较好应对UI的改变对测试用维护成本的影响。
PageObject模式原则
上一个小节,我们看到了如何使用封装好的PageObject对象。那么,应该如何来设计(封装)一个PageObject呢?下面列出了一个些PageObject设计的原则:
- 提供公共方法来表示页面提供的服务
- 尽量不要暴露页面的内部细节
- 一般不要在Page Objects中使用断言(CheckPoint),因为检查点往往是测试用例应当关心的。
- 提供页面操作的方法返回其他PageObjects
- Page Objects不需要完整的表达整个页面,也可以是一个组件。
- 相同操作的如果结果不同,应当创建不同的方法。
还是以登录页面为例:
- public class SignInPage : PageObjectBase
- {
- public SignInPage(IWebDriver driver) : base(driver)
- {
- WaitSelector.WaitingFor_ElementExists(this.Driver,By.Id("ContentPlaceHolder1_txtUsername"));
- txtUserName = new TextBox(driver, By.Id("txtUsername"));
- txtPassword = new TextBox(driver, By.Id("txtPassword"));
- btnSignIn = new Button(driver, By.XPath(".//input[@value='Sign In']"));
- }
- #region Page elements
- protected TextBox txtUserName;
- protected TextBox txtPassword;
- protected Button btnSignIn;
- #endregion Page elements
- #region Action for test case
- /// <summary>
- /// Sign In
- /// </summary>
- /// <param name="userName">User name</param>
- /// <param name="password">Password</param>
- public HomePage SignIn(string userName, string password)
- {
- this.txtUserName.Clear();
- this.txtPassword.Clear();
- this.txtUserName.SendKeys(userName);
- this.txtPassword.SendKeys(password);
- this.btnSignIn.Click();
- return new HomePage(this.Driver);
- }
- public SignInPage SignInError(string userName, string password)
- {
- this.txtUserName.Clear();
- this.txtPassword.Clear();
- this.txtUserName.SendKeys(userName);
- this.txtPassword.SendKeys(password);
- this.btnSignIn.Click();
- return new this(this.Driver);
- }
- #endregion
- }
可以看到,对于登录页面的实现。基本的页面操作(比如登录),如果行为是不同的建议提供两个不同的方法。登录成功返回的是HomePage。但是如果失败了返回的是当前页面。这样的编码方式既清晰,也同时满足了前面例子中的链式调用的简洁。
在方法的内部,我们需要处理页面的等待延时处理,元素查找等一系列与UI相关的操作。所谓Page Objects的封装,就是希望使用Page Objects的人不需要关心页面上的细节。
关于检查点,很多实现是在Page Objects内部提供了一些方法来检查,例如:
- public SignInPage CheckErrorMessage(string message)
- {
- //... ...
- Assert.True(message,"xxxx");
- return new this(this.Driver);
- }
我们来思考一下,断言检查也就是检查Check Point应该由是测试用例本身负责,还是由提供页面服务的Page Objects来负责呢?很明显我们不应该在Page Objects内部处理测试用例的检查点。下面的这种处理方式是Page Objects模式本身建议的更好的做法:
让我们以下面的这个UI为例:
- public string GetErrorMessage()
- {
- //返回页面上的错误信息
- }
- //调用代码
- ...
- var signInPage = Router.GoTo<SignInPage>();
- var errorMsg = signInPage.SignIn("user-name", "pwd").GetErrorMessage();
- 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》(未完成)
[小北De编程手记] [Lesson 02] AutoFramework构建 之 Page Objects - 设计模式的更多相关文章
- [小北De编程手记] Lesson 01 - AutoFramework构建 之 从一个简单的Demo聊起
写在最前面 这个系列的主旨是要跟大家分享一下关于自动化测试框架的构建的一些心得.这几年,做了一些自动化测试框架以及团队的构建的工作.过程中遇到了很多这样的同学,他们在学习了某一门语言和一些自动化测试的 ...
- [小北De编程手记] : Lesson 02 - Selenium For C# 之 核心对象
从这一篇开始,开始正式的介绍Selenium 以及相关的组件,本文的将讨论如下问题: Selenium基本的概念以及在企业化测试框架中的位置 Selenium核心对象(浏览器驱动) Web Drive ...
- [小北De编程手记] : Lesson 02 玩转 xUnit.Net 之 基本UnitTest & 数据驱动
关于<玩转 xUnit.Net>系列文章,我想跟大家分享的不是简单的运行一下测试用例或是介绍一下标签怎么使用(这样的文章网上很多).上一篇<Lesson 01 玩转 xUnit.Ne ...
- [小北De编程手记] : Lesson 08 - Selenium For C# 之 PageFactory & 团队构建
本文想跟大家分享的是Selenium对PageObject模式的支持和自动化测试团队的构建.<Selenium For C#>系列的文章写到这里已经接近尾声了,如果之前的文章你是一篇篇的读 ...
- [小北De编程手记] : Lesson 07 - Selenium For C# 之 窗口处理
在实际的自动化测试过程中,我们会遇见许多需要对窗口进行处理的情况.比如,点击删除某条信息的时候系统会显示一个Alert框.或者点击某个超链接时会在浏览器中打开一个新的页面.这一篇,来和大家分享一下Se ...
- [小北De编程手记] : Lesson 06 - Selenium For C# 之 流程控制
无论你是用哪一种自动化测试的驱动框架,当我们构建一个复杂应用程序的自动化测试的时候.都希望构建一个测试流程稳定,维护成本较低的自动化测试.但是,现实往往没有理想丰满.而这一篇,我会为大家讲解我们在使用 ...
- [小北De编程手记] : Lesson 01 - Selenium For C# 之 环境搭建
在我看来一个自动化测试平台的构建,是一种很好的了解开发语言,单元测试框架,自动化测试驱动,设计模式等等等的途径.因此,在下选择了自动化测试的这个话题来和大家分享一下本人关于软件开发和自动化测试的认识. ...
- [小北De编程手记] : Lesson 03 - Selenium For C# 之 元素定位
无论哪一种自动化测试的驱动框架(基于B/S,桌面应用,还是手机App).都应当具有一套优秀的元素定位技术.通常的自动化测试流程也可以简单的归结为是一个从被测试程序中识别或是定位元素以及执行操作和验证元 ...
- [小北De编程手记] : Lesson 04 - Selenium For C# 之 API 上
这一部分,我准备向大家介绍Selenium WebDriver的常用API,学习这部分内容需要大家最好有一些简单的HTML相关知识,本文主要涉及到以下内容: Selenium API:元素检查 Sel ...
随机推荐
- Maven “Failed to execute goal org.apache.maven.plugins:maven-archetype-plugin:2.4:create...”问题总结
今天学习Maven的过程中,一直遇到一个问题:用maven指令构建新项目时,一直报错,用的 Maven 3.2 , JDK 6. 构建的命令: 错误信息: 解决方案: 在StackOverFlow上找 ...
- AC自动机总结及板子(不带指针)
蒟蒻最近想学个AC自动机简直被网上的板子搞疯了,随便点开一个都是带指针的,然而平时用到指针的时候并不多,看到这些代码也完全是看不懂的状态.只好在大概理解后自己脑补(yy)了一下AC自动机的代码,居然还 ...
- 如何让Oracle释放undo表空间
如何让Oracle释放undo表空间 最佳答案 在日常的数据库维护和数据库编程中经常会遇到犹豫对大数据量做DML操作后是得ORACLE的undo表空间扩展到十几个G或者几十个G 但是这些表空间 ...
- Redis-主从配置了解
集群的作用: 主从备份, 防止主机宕机(相当于从服务器为主服务器担任备份的作用) 读写分离, 分担master的任务 任务分离, 如从服务器分别分担备份工作和计算工作 redis集群方式 星形: 众多 ...
- LoadRunner入门(一)
以LR自带的web系统为例(前提条件:已安装好lordrunner 11 ): 一.WebTours系统 是lordrunner自带一个飞机订票系统网站,支持IE浏览器 1. WebTours服务启动 ...
- EF对于已有数据库的Code First支持
EF对于已有数据库的Code First支持 原文链接 本文将逐步介绍怎样用Code First的方式基于已有数据库进行开发.Code First支持你使用C#或者VB.Net定义类.并使用数据模型标 ...
- Ubuntu16.04LTS 环境下编译安装Xen
一.编译安装xen4.6过程 操作系统使用ubuntu16.04,通过下载xen4.6的源代码并编译安装来创建xen4.6环境. 一.依赖包的安装 sudo apt-get install gcc m ...
- 远程Get,Post请求工具类
1.远程请求工具类 import java.io.*; import java.net.URL; import java.net.URLConnection; import java.util.L ...
- Qt样式表使用注意项
Qt样式表使用注意项 <1>.StyleSheet的使用StyleSheet文件的默认后缀名为qss,可以通过命令行参数-stylesheet filename.qss来设置样式表,也可以 ...
- 学习设计模式之MVC、MVP、MVVM
引言:认真学习了下广义MVC模式下前端怎么写,狭义的MVC其实是有一个变化过程:MVC MVP MVVM,网上看了很多的关于这方面的介绍,以前总是将视图数据逻辑写一个模块,最近尝试分开并用组件式的开发 ...