Каков наилучший способ использования Selenium PageObject Design Pattern
Я создаю тесты, используя Selenium 2 Web Driver с С#.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);
}
}
Большинство статей и сообщений в блогах, которые я нахожу для selenium 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 должна быть инициирована с помощью Constructor:
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);
}
Как эффективно использовать шаблон дизайна WebOriver PageObject при тестировании.
Я не могу понять это.
Ответы
Ответ 1
Использовать PageFactory.InitElements(_driver, this)
; на конструкторе вашего базового класса страницы:
public class Page
{
public IWebDriver _driver;
public Page(IWebDriver driver)
{
this._driver = driver;
PageFactory.InitElements(_driver, this);
}
}
См. Документация PageFactory
Ответ 2
Я бы избегал утверждений в тестах и придерживался метода LoginPage.signIn, который генерирует исключение в случае неудачного входа в систему. Я не знаком с NUnit, но я думаю, что он поддерживает поведение "ожидается сбой".
Лучше поддерживать логику, зависящую от страницы, в одном месте (класс страницы).
Я предполагаю, что вам придется часто модифицировать веб-интерфейс, поскольку основное приложение все равно развивается.
Ответ 3
Создайте класс браузера для создания драйверов и аналогичных функций, таких как 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();
}
}
Это небольшой пример с функцией входа в систему.
Надеюсь, это поможет, хотя и поздний ответ.