[小北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 ...
随机推荐
- 阿里云服务器怎么运行多个项目(Nginx)
server { listen 80; server_name yy.test.cn; access_log /data/wwwlogs/access_nginx.log combined; root ...
- servlet之注册登录(简写)
1.注册页面 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEn ...
- 微信小程序开发-新闻列表之新闻列表绑定
微信小程序开发-新闻列表之新闻列表绑定开发教程: 1.效果图预览 2.准备工作 在拿到效果图后不要先急着去写代码,而是要去分析一下页面的整体结构,用什么方式定位和布局.小程序里建议使用flex布局,因 ...
- 使用ide编程时候 不知为何突然光标变宽,如何恢复成原有的细竖光标
各位朋友们, 你们在编程时候有没有这样的情况: 码着码着,突然不知什么原因,光标变成这样了: 这种宽的光标,不知道怎么调都调不回去,而且网上也没有类似的问题描述 就对我们编程极其不便(因为这种光标是操 ...
- poj 3761 bubble sort (排列组合)
#include<cstdio> #include<cstring> #define ll long long #define mod 20100713 ; ll a[maxn ...
- Swift4 Json
swift4 带来了原生的json解析,它们分别是 JSONDecoder和JSONEncoder,使用起来还算方便,不过为了更方便,我把它们又进行了简单的封装: class JsonHelper { ...
- 八数码问题+路径寻找问题+bfs(隐式图的判重操作)
Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...
- oracle-使用数据泵对不同用户和不同表空间的数据迁移
oracle-使用数据泵对不同用户和不同表空间的数据迁移 ---------------------------------------------------2013/11/13 expdp和imp ...
- 解决:wordpress error establishing a database connection problem
我是个网站菜鸟,刚开始搭建LAMP环境的时候,就要了我半条老命. 没办法,懂的东西太少,LAMP是什么我都不懂,域名是什么,我也被不懂,为什么想要有个网站就要有服务器我还是不懂.一步步地自己去钻,去看 ...
- HTML5——css基础语法
1.了解CSS CSS是一种用来表现HTML等文件样式的计算机语言,是对HTMl文件中设置的各种标签添加各种各样的样式与表达方式,让网页更生动,更美观. 2.导入CSS的三种方式 1.行内样式表:直接 ...