繁体   English   中英

带有页面对象模型的 Specflow 中的常见步骤定义

[英]Common Step Definitions in Specflow with Page Object Model

我的登录页面绑定中有一个步骤定义

[When(@"I click the '(.*)' button")]
public void IClickTheButton(string buttonName)
{
    LoginPage loginPage = new LoginPage();
    loginPage.ClickTheButton(buttonName);
}

我的页面对象是使用 BasePage 中的ClickTheButton方法设置的:

public class LoginPage : BasePage
{
    public LoginPage(IWebDriver _driver)
    {
        driver = _driver;
    }
    // some methods

}
public class HomePage : BasePage
{
    public HomePage(IWebDriver _driver)
    {
        driver = _driver;
    }
    // some methods
}
public class BasePage
{
    //no constructor atm
    public void ClickTheButton(string buttonName)
    {
        driver.GetFirstButtonWithTextContaining(buttonName).Click();
    }
    // more methods
}      

应用程序中的所有按钮的格式都相同,因此GetFirstButtonWithTextContaining方法将使用

driver.FindElements(By.TagName("button")).Where(x => x.Text == buttonName).First();

问题是我将在我所有的功能文件中使用“我点击‘(.*)’按钮”,比如主页功能,所以使用登录页面步骤定义似乎不正确,它利用了登录实例其他页面上所有按钮的页面类。

我正在考虑为这些类型的方法创建一个通用步骤 defs 文件,但是当我向 BasePage 添加一个构造函数(与其他页面对象类相同)并在通用步骤 defs 绑定中执行以下操作时:

BasePage basePage = new BasePage();
basePage.ClickTheButton(buttonName);

有更好的实现吗?...使用 BasePage 类似乎是错误的,但我看不到在使用页面对象时如何跨多个功能共享步骤定义。 我正在尝试创建尽可能多的通用步骤以在所有功能之间共享。

您的页面模型并不是真正的页面模型。 它们只是使用 Selenium 做事情的方便包装器,并没有提供良好的抽象层。

直接在步骤定义中使用扩展方法:

[When(@"I click the '(.*)' button")]
public void IClickTheButton(string buttonName)
{
    driver.GetFirstButtonWithTextContaining(buttonName).Click();
}

或者重写你的页面模型来封装页面上的用户操作:

public class LoginPage
{
    private readonly IWebDriver driver;
    private IWebElement Password => driver.FindElement(By.Id("Password"));
    private IWebElement Username => driver.FindElement(By.Id("Username"));
    private IWebElement LoginButton => driver.FindElement(By.XPath("//button[contains(., 'Log In')]"));

    public LoginPage(IWebDriver driver)
    {
        this.driver = driver;
    }

    public HomePage Login(string username, string password = "test")
    {
        Username.SendKeys(username);
        Password.SendKeys(password);
        LoginButton.Click();

        var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));

        wait.Until(ExpectedConditions.StalenessOf(LoginButton));

        return new HomePage(driver);
    }
}

这意味着将您的步骤从程序风格(我点击这个;我这样做)更改为更加行为驱动的风格。 例如,使用程序步骤“登录”是很常见的:

Given I am on the login page
When I enter "foo" for the "Username"
And I enter "bar" for the "Password"
And I click the "Log In" button

相反,行为驱动的步骤将是一个快速的单行代码,将其大部分行为委托给页面模型:

Given I am logged in as "foo"

[Given(@"I am logged in as ""(.+)""")]
public GivenIAmLoggedInAs(string username)
{
    var loginPage = new LoginPage(driver);

    loginPage.LogIn(username);
}

您的黄瓜步骤应该是一层薄薄的贴面,将特征文件中的应用程序行为描述粘合到将行为封装在页面中的页面模型上。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM