使用Selenium PageObject设计模式的最佳方法是什么

我正在使用Selenium 2 Web Driver和C#.Net创建测试。 在阅读了很多Selenium文档之后,我仍然不确定如何使用PageObject设计模式进行测试。

许多selenium示例仅在Java中显示,并且.Net的API绑定并不总是与人们认为的相似,这是由于某些语言设置的限制和标准。

在.Net Selenium Web Driver中将PageObject设计模式与PageFactory一起使用的最佳方法是什么?

最终,我希望我的PageObjects能够处理更多function,而不是使用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); } } 

我找到的关于selenium webdriver Design Patterns的大多数文章和博客文章都给我发现的先前post带来了矛盾。

那么,正确的方法是什么?

最重要的是,我甚至尝试了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设计模式进行测试。 我无法弄清楚这一点。

使用PageFactory.InitElements(_driver, this) ; 在基页类的构造函数上:

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

请参阅PageFactory文档

我会避免在测试中使用Asserts并坚持使用LoginPage.signIn方法,该方法会在登录失败时抛出exception。 我不熟悉NUnit,但我猜它支持“预期失败”的行为。

最好将依赖于页面的逻辑保存在一个位置(页面类)。

我猜你必须在主要应用程序发展过程中大量修改Web UI测试。

创建一个Browser类来创建驱动程序和类似的function,例如用于导航的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(); } } 

这是一个具有登录function的小例子。 我希望这可能会有所帮助,即使是迟到的回复。