BDD - SpecFlow Page Object Model POM

引言

前面文章《 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:

<input id="txtUrl" name="Url" type="text" value="">

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:

<input id="txtUrl" name="Url" type="text" value="">

Code:

public class PageObject
{
    private IWebDriver _webDriver;
    private Lazy<IWebElement> _txtUrl;

    public PageObject(IWebDriver webDriver)
    {
        _webDriver = webDriver;
        _txtUrl = new Lazy<IWebElement>(() => _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:

<div class='A'>
    <div class='B'/>
</div>
<div class='B'>
</div>

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<IWebElement> _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:

<div class='A'>
</div>
<div class='B'>
</div>

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"));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值