BDD - SpecFlow Page Object Model POM
创始人
2024-01-25 07:02:23
0

BDD - SpecFlow Page Object Model

  • 引言
  • POM 优势
  • POM 简单实现
  • POM 缓存实现
  • POM 层次实现
    • Parent - Child 关系
    • Component 关系

引言

前面文章《 BDD - SpecFlow Web UI 测试实践 》就运用到 Page Object Model,简称 POM,POM 是一种模式,结合 Selenium 用来抽取 Web UI,使得 UI 自动测试更易实现,今天就来详细介绍一下 POM 。

POM 优势

当运用 Selenium 时,总是用 WebElements 来访问不页面上不同的元素。可以利用 WebDriver 类中的方法 FindElement 和 FindElements 来定位到这些 WebElements。

如果你总是直接在 automation code 里直接使用这些方法,会造成大量的重复代码。这个时候就得考虑用 POM 了,将调用 FindElement(s) 方法隐藏在一个类里。

使用 POM 的好处:

  • 使得这些隐藏 FindElement(s) 方法的类重用
  • 如果 UI Element 有变化,只需修改一个地方
  • 减少 Binding 类对 HTML 结构的依赖

POM 简单实现

HTML:


Code:

public class PageObject
{private IWebDriver _webDriver;public PageObject(IWebDriver webDriver){_webDriver = webDriver;}public IWebElement txtUrl => _webDriver.FindElement(By.Id("txtUrl"));
}

public 构造函数中传入 WebDriver 实例,这个 WebDriver 依赖注入,详情参考 《 BDD - SpecFlow Context Injection 上下文依赖注入 》,当访问 TxtUrl 属性时,WebDriver 将在整个 Page 搜索 id 为 txtUrl 的 Element。注意,这里没有涉及到缓存,也就是说每次访问 TxtUrl 属性时,WebDriver 都会重新搜索一遍。

POM 缓存实现

HTML:


Code:

public class PageObject
{private IWebDriver _webDriver;private Lazy _txtUrl;public PageObject(IWebDriver webDriver){_webDriver = webDriver;_txtUrl = new Lazy(() => _webDriver.FindElement(By.Id("txtUrl")));}public IWebElement txtUrl => _txtUrl.Value;
}

还是在 public 构造函数中传入 WebDriver 实例,进行 WebDriver 依赖注入。只是利用 Lazy 这种简单的方式将 FindElement 方法的结果缓存起来。

只有第一次访问 txtUrl 属性时,才会触发调用 FindElement 方法,后面访问 txtUrl 属性时,只会返回第一次访问时缓存的值。这样有助于节省自动化执行时间,因为 WebDriver 针对同一 Element 只需搜索一次。

注意,如果你使用上面的缓存模式,当心页面和页面元素的生命周期。如果页面有发生变化,不要用老的 Element 对象。

POM 层次实现

Parent - Child 关系

HTML:

Code:

public class ParentPageObject
{private IWebDriver _webDriver;public ParentPageObject(IWebDriver webDriver){_webDriver = webDriver;}public IWebElement WebElement => _webDriver.FindElement(By.ClassName("A"));public ChildPageObject Child => new ChildPageObject(WebElement);
}public class ChildPageObject
{private IWebElement _webElement;private Lazy _txtUrl;public ChildPageObject(IWebElement webElement){_webElement = webElement;}public IWebElement WebElement => _webElement.FindElement(By.ClassName("B"));
}

本例中,我们稍微调整一下 HTML 文档,两个 div 元素有相同的 class 属性 B 值,但是我们只想为具有 class A 属性的 div 元素及其子元素创建 PageObject。

就好比一个或多个页面有相同的元素组件一样,我们可以分层次创建 POM 类。我们可以将元素组件单独创建 POM 类,作为 ParentPageObject 类的 ChildPageObject。

如果我们用相同的 WebDriver.FindElement 方法,我们将得到与 A div在同一层的 div元素。

但是每个 WebElement 都有 FindElement(s) 方法,使得我们可以在整个 HTML 文档的局部范围内定位元素。
所以我们可以通过传 parent- WebElement 到 ChildPageObject 类,只定位 A-div 内部的 B-div。

Component 关系

上面是采用 Parent - Child 层次结构,当然也可以 Component 层次结构,将HTML 文档稍微改一下,div A 和 div B 分别是 component,HomePageObject 分别包含 ComponentAPageObject 和 ComponentBPageObject。

HTML:

Code:

public class HomePageObject
{private IWebDriver _webDriver;public ParentPageObject(IWebDriver webDriver){_webDriver = webDriver;}public ComponentAPageObject componentA => new ComponentAPageObject(_webDriver);public ComponentBPageObject componentB => new ComponentBPageObject(_webDriver);}
public class ComponentAPageObject
{private IWebDriver _webDriver;public ParentPageObject(IWebDriver webDriver){_webDriver = webDriver;}public IWebElement WebElement => _webDriver.FindElement(By.ClassName("A"));
}public class ComponetBPageObject
{private IWebDriver _webDriver;public ParentPageObject(IWebDriver webDriver){_webDriver = webDriver;}public IWebElement WebElement => _webDriver .FindElement(By.ClassName("B"));
}

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...