[小北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 ...
随机推荐
- Tomcat结构(转)
资料:http://wenku.baidu.com/view/20720e78a26925c52cc5bfd6.html Tomcat系统架构 http://wenku.baidu.com/view/ ...
- 文科生细谈学习Linux系统的重要性
首先大概介绍下自己,我学的是公共事业管理方面的专业,可以说是面向纯理论,社区管理社会管理的专业,但是从大二开始,对网络及服务器运维方面产生浓厚兴趣,并不断在网上找相关资料. 在这期间经历过很多,单说桌 ...
- 再起航,我的学习笔记之JavaScript设计模式03
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 上一 ...
- vc类型转换函数大全
windows c++中存在各种类型,在实际应用过程中也需要将类型互相转换,故整理了常用类型之间的转换并将之封装成函数,仅供参考,有什么不对的地方,还请指正! ****************** ...
- code_smith生成实体类
- 解决js中post提交数据并且跳转到指定页面的问题总结
今天在开发中过程中遇到了这个问题,js中利用JQuery中的 $.post("url", id, function(){}); 这个方法是数据提交正常,但是后台处理完成之后跳转无法 ...
- HTML的正确入门姿势——基本结构与基本标签
一.什么是HTML HTML是超文本标签语言,即网页的源码.而浏览器就是翻译解释HTML源码的工具. 二.HTML文档的结构 HTML文档主要包括三大部分:文档声明部分.<head>头部部 ...
- android学习ProgressBar的简单使用
android 提供的ProgressBar控件分为两种,一种是不带进度的进度条,一种是带进度的进度条,如果可以计算任务的完成量那么就用带进度条的,如果无法计算任务量,那么就使用不带进度的进度条.Pr ...
- 【转】C++静态库与动态库
C++静态库与动态库 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一 ...
- nopCommerce安装教程
nopCommerce是一个通用的电子商务平台,适合每个商家的需要:它强大的企业和小型企业网站遍布世界各地的公司销售实体和数字商品.nopCommerce是一个透明且结构良好的解决方案,它结合了开源和 ...