前面文章《 BDD - SpecFlow Web UI 测试实践 》就运用到 Page Object Model,简称 POM,POM 是一种模式,结合 Selenium 用来抽取 Web UI,使得 UI 自动测试更易实现,今天就来详细介绍一下 POM 。
当运用 Selenium 时,总是用 WebElements 来访问不页面上不同的元素。可以利用 WebDriver 类中的方法 FindElement 和 FindElements 来定位到这些 WebElements。
如果你总是直接在 automation code 里直接使用这些方法,会造成大量的重复代码。这个时候就得考虑用 POM 了,将调用 FindElement(s) 方法隐藏在一个类里。
使用 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 都会重新搜索一遍。
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 对象。
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。
上面是采用 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"));
}
上一篇:货币银行学试卷及答案