28

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

Многие примеры селена показаны только на 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); 
    } 

} 

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

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

Для этого я даже попробовал шаблон дизайна PageObject.

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

Внутри моей LoginPage

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 дизайн шаблона эффективно тестирование. Я не могу понять это.

ответ

16

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

public class Page 
{ 
    public IWebDriver _driver; 

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

Пожалуйста, смотрите PageFactory documentation

+0

Да, это та структура, с которой я закончил, когда начал проект. +1 –

+4

вопрос, как бы вы сделали, если элемент 'Select' (dropdownlist) в pageobject? мне сказали, что вы не можете использовать pageobject для select (dropdownlist), это правда? –

+0

Может кто-то ответить на вопрос @Nick Kahn :) :) У меня такая же проблема. –

1

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

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

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

+1

Спасибо за ответ, но это все еще не объясняет, как использовать конструктор проекта для объекта страницы, или почему способ, которым я его использую, вызывает ошибки, такие как webdriver, игнорирующий загрузку страницы (так как это должно делать это автоматически) и почему он отключает загрузку страницы, когда я нажимаю submit. Мне кажется, что это происходит, когда я возвращаю новый объект PageObject, но я все еще передаю ссылку на один и тот же веб-драйвер, поэтому я не вижу, что я делаю неправильно. Весь этот шаблонный шаблонный рисунок требует больше документации на вики селена. =/ –

+0

Я также согласен с вашим советом по утверждениям, он поддерживает ожидаемые исключения, шаг за шагом. Пока кто-нибудь не сможет просветить меня по этому вопросу –

+0

Я неправильно понял вопрос, извините :) – Bond

1

Создать класс браузера, чтобы создать драйвер и аналогичные функции, такие как 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(); 
     } 
} 

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

+0

Вышеупомянутое относится к структуре, и было бы лучше, если бы вы использовали Microsoft Visual Studio Unit Test Framework для создания тестов, вызывающих функцию страниц в созданных модульных тестах. – user3687440

+0

можете ли вы использовать код, используемый для метода Browser.WaitForElement? Кроме того, как вы получаете IWebDriver из IWebElement, созданного через объект страницы? –

Смежные вопросы