Как лучше всего использовать шаблон проектирования Selenium PageObject? - PullRequest
29 голосов
/ 16 ноября 2011

Я создаю тесты, используя Selenium 2 Web Driver с C # .Net. Прочитав большую часть документации Selenium, я все еще не уверен в том, как проводить тестирование с использованием шаблонов проектирования PageObject.

Многие примеры селена показаны только в Java, и привязки API для .Net не всегда настолько похожи, как можно было бы подумать, что они связаны с ограничениями и стандартами, установленными определенными языками.

Как лучше всего использовать шаблон проектирования PageObject с PageFactory в .Net Selenium Web Driver?

В конце концов, я хочу, чтобы мои PageObjects обрабатывали больше функциональности, а не мои тесты NUnit с использованием PageObject IWebElements.

Ниже приведен пример того, как я собираюсь создавать свои тесты в будущем.

public class LoginPage
{
    private IWebDriver webDriver;

    [FindsBy(How = How.Id, Using = "ctl00_ctl00_ctl00_insideForm_insideForm_content_txtPassword")]
    public IWebElement Password { get; set; }

    [FindsBy(How = How.Id, Using = "ctl00_ctl00_ctl00_insideForm_insideForm_content_cmdSubmit")]
    public IWebElement SubmitButton { get; set; }

    [FindsBy(How = How.Id, Using = "ctl00_ctl00_ctl00_insideForm_insideForm_content_txtUserName")]
    public IWebElement UserName { get; set; }

    public LoginPage() { }

    public LoginPage(IWebDriver webDriver)
    {
        this.webDriver = webDriver;


        if(!webDriver.Url.Contains("Login.aspx"))
        {
            throw new StaleElementReferenceException("This is not the login page");
        }
        PageFactory.InitElements(webDriver, this);
    }

    public HomePage signIn(string username, string password)
    {
        UserName.SendKeys(username);
        Password.SendKeys(password);
        SubmitButton.Submit();

        // Even if i create a NUnit test for this
        // Issue with page loading still occures when I try and return new object
        HomePage homePage = new HomePage(webDriver);
        PageFactory.InitElements(webDriver, homePage);
        return homePage;
    }
}

На данный момент это то, что я сейчас делаю с NUnit:

[TestFixture]
public class LoginPageTest : TestBase
{
    private IWebDriver driver;
    private LoginPage loginPage;
    private HomePage homePage;

    [SetUp]
    [Description("Sets up the test fixture page objects and navigates to the login page.")]
    public void SetUp()
    {
        driver = StartDriver();
        Log.Info("Driver started");
        driver.Navigate().GoToUrl("http://" + Environment + ");
        loginPage = new LoginPage();
        PageFactory.InitElements(driver, loginPage);
        //driver.Navigate().Refresh();
    }

    [Test]
    [Description("Enters invalid credentials and asserts that a correct error message is displayed.")]
    public void SubmitFormInvalidCredentials()
    {
        loginPage.UserName.SendKeys("invalid");
        loginPage.Password.SendKeys("invalid");
        loginPage.SubmitButton.Click();
        IWebElement invalidCredentials = driver.FindElement(By.Id("ctl00_ctl00_ctl00_insideForm_insideForm_ctl02_title"));
        Assert.AreEqual("Invalid user name or password", invalidCredentials.Text);
    }

    [Test]
    [Description("Enters valid credentials and asserts that the user is taken to the home page.")]
    public void SubmitFormValidCredentials()
    {
        loginPage.UserName.SendKeys("valid");
        loginPage.Password.SendKeys("valid");
        loginPage.SubmitButton.Click();

        homePage = new HomePage();
        PageFactory.InitElements(driver, homePage);
        Assert.AreEqual("pattest", homePage.Username.Text);
    }

 }

Большинство статей и постов в блогах, которые я нахожу для шаблонов проектирования селенового вебдрайвера, противоречат предыдущим постам, которые я нахожу.

Итак, каков правильный путь?

В довершение всего я даже попробовал шаблон проектирования PageObject.

    [Test]
    [Description("Login using PageObject Design Pattern")]
    public void Login()
    {
        loginPage = new LoginPage(driver);
        HomePage signIn = loginPage.SignIn("pattest", "pattest");
    }

Внутри моей страницы входа в систему

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

        if (!driver.Url.Contains("Login.aspx"))
        {
            throw new ElementNotFoundException("This is not the login page");
        }
        PageFactory.InitElements(driver, this);
    }

    public HomePage SignIn(string username, string password)
    {
        UserName.SendKeys(username);
        Password.SendKeys(password);
        SubmitButton.Click();
        return new HomePage(driver);
    }

И, конечно, чтобы показать, как моя HomePage должна быть инициирована с помощью Конструктора:

public HomePage(IWebDriver d)
    {
        webDriver = d;
        // I need to use this as its not freaking waiting for my Page to load when I pass the webdriver in the consturctor.
        var wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(60));

        try
        {
            wait.Until(driver => driver.FindElement(By.Id("ctl00_ctl00_ctl00_insideForm_insideForm_loginStatus")));
        }
        catch(Exception e)
        {
            throw new ElementNotFoundException("This is not the home page.");
        }
        PageFactory.InitElements(webDriver, this);
    }

Как эффективно использовать шаблон проектирования WebDriver PageObject при тестировании. Я не могу понять это.

Ответы [ 3 ]

18 голосов
/ 29 мая 2012

Использование PageFactory.InitElements(_driver, this); на конструкторе класса вашей базовой страницы:

public class Page
{
    public IWebDriver _driver;

    public Page(IWebDriver driver)
    {
        this._driver = driver;
        PageFactory.InitElements(_driver, this);
    }
}

Пожалуйста, смотрите документацию PageFactory

1 голос
/ 28 мая 2015

Создайте класс Browser для создания драйвера и аналогичные функции, такие как GoTo () для навигации и Teardown () для закрытия браузера.

public class Browser
    {
        static IWebDriver webDriver = new FirefoxDriver();
        //static IWebDriver webDriver = new ChromeDriver();
        //InternetExplorerOptions  options = new InternetExplorerOptions(); 
        //static IWebDriver webDriver = new InternetExplorerDriver(@"C:\Program Files\Selenium\");
        public static void GoTo(string url)
        {
            //webDriver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 5));
            webDriver.Url = url;
        }
        public static ISearchContext Driver
        {
            get { return webDriver; }
        }
        public static void Teardown()
        {
            webDriver.Quit();
        }   
        public static void MaximizeWindow()
        {
            webDriver.Manage().Window.Maximize();
        }

Создание отдельных классов для страниц и использование PageFactory для инициализации элементов.

 public class Admin
    {
        public static AdminPage AdminPage
        {
            get
            {
                var adminpage = new AdminPage();
                PageFactory.InitElements(Browser.Driver, adminpage);
                return adminpage;
            }

        }
    }
    public class AdminPage
    {
        string Url = "http://172.18.12.225:4444/admin/admin.aspx";
        string Title = "Login";
        string Text = "Admin";
        public void GoTo()
        {
            Browser.GoTo(Url);
        }
        public bool IsAt()
        {
            return Browser.Title == Title;
        }
        public bool Is_At()
        {
            return Browser.Title == Text;
        }
        [FindsBy(How = How.Id, Using = "ctl16_lblUdpSageMesageCustom")]
        public IWebElement UpdateMessage { get; set; }

        [FindsBy(How = How.Id, Using = "hypPreview")]
        public IWebElement BackHomeLink { get; set; }
        //Login
       // [FindsBy(How = How.Id, Using = "ctl14_UserName")]
       // public IWebElement UserNameLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_Password")][CacheLookup]
        public IWebElement PasswordLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_LoginButton")][CacheLookup]
        public IWebElement LoginLink { get; set; }
        //Forgot Password
        [FindsBy(How = How.Id, Using = "ctl14_hypForgotPassword")][CacheLookup]
        public IWebElement FPWLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_wzdForgotPassword_txtUsername")][CacheLookup]
        public IWebElement FPWUserNameLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_wzdForgotPassword_CaptchaValue")][CacheLookup]
        public IWebElement FPWCaptchaLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_wzdForgotPassword_StartNavigationTemplateContainerID_StartNextButton")][CacheLookup]
        public IWebElement FPWNextLink { get; set; }
        [FindsBy(How = How.Id, Using = "ctl14_wzdForgotPassword_StartNavigationTemplateContainerID_CancelButton")][CacheLookup]
        public IWebElement FPWCancelLink { get; set; }
        [FindsBy(How = How.Id, Using = "sfToppane")][CacheLookup]
        public IWebElement TopPane { get; set; }
        [FindsBy(How = How.Id, Using = "sidebar")][CacheLookup]
        public IWebElement sidebar { get; set; }
        //Role
        //[FindsBy(How = How.Id, Using = "ctl19_rptDashBoard_ctl01_hypPageURL")]
        //public IWebElement Role { get; set; }       
        //User
        //[FindsBy(How = How.Id, Using = "ctl19_rptDashBoard_ctl02_hypPageURL")]
        //public IWebElement User { get; set; } 
        public void LogIn(string Username, string Password)
        {
            Browser.MaximizeWindow();
            IWebElement UserNameLink = Browser.WaitForElement(By.Id("ctl14_UserName"), 15);
            UserNameLink.Click();
            UserNameLink.Clear();
            UserNameLink.SendKeys(Username);
            PasswordLink.Click();
            PasswordLink.Clear();
            PasswordLink.SendKeys(Password);
            LoginLink.Click();
        }
}

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

1 голос
/ 16 ноября 2011

Я бы избегал утверждений в тестах и ​​придерживался метода LoginPage.signIn, который выдает исключение в случае неудачного входа в систему. Я не знаком с NUnit, но думаю, что он поддерживает поведение «ожидается сбой».

Лучше хранить зависимую от страницы логику в одном месте (класс страницы).

Полагаю, вам придется много изменять тесты веб-интерфейса, так как основное приложение все равно развивается.

...