2011-11-16 123 views
28

我使用Selenium 2 Web Driver與C#.Net創建測試。在閱讀了很多Selenium文檔後,我仍然不確定如何使用PageObject設計模式進行測試。什麼是使用Selenium PageObject設計模式的最佳方式

許多selenium示例僅在Java中顯示,.Net的API綁定並非總是如人們所認爲的那樣相似,這是由於某些語言設置的限制和標準。

在.Net Selenium Web驅動程序中使用PageObject設計模式和PageFactory的最佳方式是什麼?

最終,我希望我的PageObjects能夠處理更多的功能,而不是使用PageObject IWebElements的NUnit測試。

下面是我如何創建我的測試前進的示例。

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設計模式發出矛盾,以前的文章,我覺得。

那麼,什麼是正確的方式?

爲了解決這個問題,我甚至給了PageObject設計模式一個嘗試。

​​

裏面我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); 
    } 

,當然以顯示如何我的主頁應該有它的構造函數初始化:

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

問題,如果元素是pageobject中的「Select」(dropdownlist),你會怎麼做?我被告知,你不能使用pageobject進行選擇(dropdownlist)是真的嗎? –

+0

有人可以回答@尼克卡恩的問題:)我有同樣的問題。 –

1

我會避免在測試中斷言並堅持使用LoginPage.signIn方法,該方法會在登錄失敗時引發異常。我不熟悉NUnit,但我想它支持'預計失敗'的行爲。

最好將頁面相關邏輯保存在一個地方(頁面類)。

我猜你必須隨着主應用程序的發展而修改Web UI測試。

+1

感謝您的回覆,但這仍然不能解釋如何使用頁面對象設計模式或爲什麼我會使用它的方式,導致錯誤,如webdriver忽略頁面加載,(因爲它應該這樣做自動)以及爲什麼當我點擊提交時切斷加載頁面。 在我看來,它發生在我返回一個新的PageObject的時候,但我還在傳遞對同一個Web驅動程序的引用,所以我沒有看到我做錯了什麼。 這整個pageobject設計模式的東西真的需要更多的硒維基文檔。 =/ –

+0

我也同意你對斷言的建議,它一次只支持預期的異常。直到有人可以在這個特殊問題上給我啓發 –

+0

我誤解了這個問題,對不起:) – Bond

1

創建一個瀏覽器類來創建驅動程序和類似的功能,如轉到()用於導航和拆解()關閉瀏覽器。 `

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單元測試框架創建測試,並在創建的單元測試中調用頁面的功能,將會更好。 – user3687440

+0

你能分享用於Browser.WaitForElement方法的代碼嗎?另外,如何從通過頁面對象創建的IWebElement獲取IWebDriver? –

相關問題