Общие определения шагов в Specflow с объектной моделью страницы - PullRequest
1 голос
/ 09 февраля 2020

У меня есть определение шага в привязках моей страницы входа в систему

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

Объекты «Моя страница» настроены с помощью метода ClickTheButton в BasePage:

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
}      

Все кнопки в приложении отформатированы одинаково, поэтому метод GetFirstButtonWithTextConisting будет щелкать их все, используя

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

Проблема в том, что я буду использовать «Я нажимаю» (. *) 'button' во всех моих файлах функций, таких как функция HomePage, поэтому кажется неправильным использовать определение шага страницы входа в систему, которое использует экземпляр класса страницы входа для всех кнопок на других страницах.

Я думал о создании файла общего шага defs для методов этого типа, но когда я добавляю конструктор в BasePage (аналогично другим классам объектов страницы) и делаю следующее в привязке общего шага defs:

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

Есть ли лучшая реализация? ... просто кажется неправильным использовать класс BasePage, но я не вижу, как разделить определение шага между несколькими функциями при использовании объектов страницы. Я пытаюсь создать как можно больше общих шагов для всех функций.

1 Ответ

2 голосов
/ 10 февраля 2020

Ваши модели страниц на самом деле не являются моделями страниц. Они просто удобные обертки для работы с 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);
}

Ваши шаги огурца должны быть тонким шпоном, связывающим описание поведения приложения в ваших файлах функций с моделями страниц, которые инкапсулируют это поведение на странице.

...