我开始在Selenium .NET驱动程序上实现PageFactory设计模式。我有一个名为example“ButtonControl”的Page对象类,我希望将其视为IWebElement。
默认看起来像:
[FindsBy(How = How.CssSelector, Using = "someSelector")]
public IWebElement button1;
我真正想要的是:
// in the page object:
[FindsBy(How = How.CssSelector, Using = "someSelector")]
public ButtonControl button1;
// in test code:
page.button1.Click();
所以我需要的是......我不知道。也许自定义工厂会创建这个页面对象?
有什么想法吗?
答案 0 :(得分:0)
Page object model应该只保留UI元素的地图,仅此而已。在许多文章中,您会看到建议将方法与页面进行交互 - 但这是错误的。
/**
* Page Object encapsulates the Sign-in page.
*/
public class LoginPage{
private final WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
// Check that we're on the right page.
if (!"Login".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps logging out first
throw new IllegalStateException("This is not the login page");
}
}
// The login page contains several HTML elements that will be represented as WebElements.
// The locators for these elements should only be defined once.
By usernameLocator = By.id("username");
By passwordLocator = By.id("passwd");
By loginButtonLocator = By.id("login");
/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/
public LoginPage loginValidUser(String userName, String password) {
driver.findElement(usernameLocator).sendKeys(userName);
driver.findElement(usernameLocator).sendKeys(password);
driver.findElement(loginButtonLocator).click();
return new HomePage(selenium);
}
}
这违反SRP,在上面的示例中,您有两个原因需要更改 - 如果更改了定位器并且流程已更改。恕我直言,大多数时候是智能测试和智能页面对象之间的权衡。但您可以实现 Action 类,该类将负责与页面的交互。
答案 1 :(得分:0)
对于PageObject来说,这确实是一个很棒的主意。 :)
您可以使用以下库:https://github.com/DotNetSeleniumTools/DotNetSeleniumExtras 扩展类https://github.com/DotNetSeleniumTools/DotNetSeleniumExtras/blob/master/src/PageObjects/DefaultPageObjectMemberDecorator.cs
您的班级选择应该是这样的:
import re
def count_substring(string, sub_string):
count=len(re.findall('(?='+sub_string+')', string))
return count
还需要初始化页面:
class CustomPageObjectMemberDecorator : DefaultPageObjectMemberDecorator, IPageObjectMemberDecorator
{
private BaseDriver driver;
public CustomPageObjectMemberDecorator(BaseDriver driver) => this.driver = driver;
public new object Decorate(MemberInfo member, IElementLocator locator)
{
FieldInfo field = member as FieldInfo;
PropertyInfo property = member as PropertyInfo;
Type targetType = null;
if (field != null)
{
targetType = field.FieldType;
}
bool hasPropertySet = false;
if (property != null)
{
hasPropertySet = property.CanWrite;
targetType = property.PropertyType;
}
var genericType = targetType.GetGenericArguments().FirstOrDefault();
if (field == null & (property == null || !hasPropertySet))
{
return null;
}
// IList<IWebElement>
if (targetType == typeof(IList<IWebElement>))
{
return base.Decorate(member, locator);
}
// IWebElement
else if (targetType == typeof(IWebElement))
{
return base.Decorate(member, locator);
}
// BaseElement and childs
else if (typeof(BaseElement).IsAssignableFrom(targetType))
{
var bys = CreateLocatorList(member);
var cache = ShouldCacheLookup(member);
IWebElement webElement = (IWebElement)WebElementProxy.CreateProxy(locator, bys, cache);
return GetElement(targetType, webElement, driver, field.Name);
}
// IList<BaseElement> and childs
else if (targetType.GetInterfaces().FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>)) != null)
{
Type elementOfListTargetType = targetType.GetGenericArguments()[0];
if (typeof(BaseElement).IsAssignableFrom(elementOfListTargetType))
{
var cache = ShouldCacheLookup(member);
IList<By> bys = CreateLocatorList(member);
if (bys.Count > 0)
{
return CustomElementListProxy.CreateProxy(driver, field.Name, elementOfListTargetType, locator, bys, cache);
}
else
{
return null;
}
}
else
{
return null;
}
}
else
{
return null;
}
}
private Element GetElement(Type type, IWebElement webElement, BaseDriver baseDriver, string Name)
{
return (Element)type
.GetConstructor(new[] { typeof(IWebElement), typeof(BaseDriver), typeof(string) })
.Invoke(new object[] { webElement, baseDriver, Name });
}
}
您的PageObject将如下所示:
public BasePage(BaseDriver Driver) : base(Driver)
{
IPageObjectMemberDecorator pageObjectMemberDecorator = new CustomPageObjectMemberDecorator(_driver);
PageFactory.InitElements(this, _driver.RetryingElementLocator, pageObjectMemberDecorator);
}
还可以扩展FindByAttribute,而PageObject将得到简化:
public class LoginPage : BasePage, ILoad
{
[FindsBy(How = How.XPath, Using = "//*[@class = 'linkButtonFixedHeader office-signIn']")] private Button SignIn;
[FindsBy(How = How.XPath, Using = "//input[@type = 'email']")] private TextInputField Email;
[FindsBy(How = How.XPath, Using = "//input[@type = 'submit']")] private Button Submit;
[FindsBy(How = How.XPath, Using = "//input[@type = 'password']")] private TextInputField Password;
public LoginPage() : base(new BaseDriver(), "https://outlook.live.com/")
{
}
public bool IsLoaded() =>
SignIn.IsVisible() &&
Email.IsVisible() &&
Submit.IsVisible();
public MainMailPage PositiveLogin(User user)
{
SignIn.Click();
Email.SendString(user.Login);
Submit.Click();
Password.SendString(user.Pass);
Submit.Click();
return Page<MainMailPage>();
}
}