Art*_*hur 5 java selenium webdriver
我试图从中得到:
@FindBy(xpath = "//div/span/img")
public WebElement addNew;
@FindBy(xpath = "//tr[2]/td[12]")
public WebElement save;
@FindBy(xpath = "//td/div/input")
public WebElement entryIdel;
@FindBy(xpath = "//textarea")
public WebElement authorFieldel;
@FindBy(xpath = "//td[3]/div/textarea")
public WebElement titleFieldel;
Run Code Online (Sandbox Code Playgroud)
那:
@FindBy(xpath = "//div/span/img")
public Button addNew;
@FindBy(xpath = "//tr[2]/td[12]")
public Button save;
@FindBy(xpath = "//td/div/input")
public InputBox entryIdel;
@FindBy(xpath = "//textarea")
public InputBox authorFieldel;
@FindBy(xpath = "//td[3]/div/textarea")
public InputBox titleFieldel;
Run Code Online (Sandbox Code Playgroud)
我以前为每个元素创建了类,但当然没有任何反应.我如何创建我的元素类,以便我可以使用它而不是WebElement?
这里是InputBox的代码:
import org.openqa.selenium.WebElement;
public class InputBox {
protected WebElement element;
public WebElement getElement() {
return element;
}
public InputBox(WebElement element) {
this.element = element;
// TODO Auto-generated constructor stub
}
public void type(String input) {
clearText();
element.sendKeys(input);
}
public void clearText() {
element.clear();
}
public boolean isEditable() {
return element.isEnabled();
}
String getText() {
return element.getText();
}
String getValue() {
return element.getValue();
}
}
Run Code Online (Sandbox Code Playgroud)
创建FieldDecorator的新实现.
当您使用PageFactory时,您可能正在调用
public static void initElements(ElementLocatorFactory factory, Object page)
Run Code Online (Sandbox Code Playgroud)
这将成为
public static void initElements(FieldDecorator decorator, Object page)
Run Code Online (Sandbox Code Playgroud)
除了在自定义类型中包装代理外,FieldDecorator的行为与DefaultFieldDecorator类似.
看这里的课程[来源]
小智 6
我发现了一篇非常有趣的帖子,关于@FindBy如何工作以及如何在Selenium(WebDriver)测试中使用FieldDecorator:http://habrahabr.ru/post/134462/ .
这篇文章的作者是РоманОразмагомедов(Roman Orazmagomedof).
在这里,我将提供有关如何使用FieldDecorator的更多说明.此外,我将展示原始实现的扩展版本以及其他功能,这将允许使用ExpectedCondition接口等待装饰字段准备就绪.
设定目标
Selenium页面对象模式的大多数插图都使用WebElement接口来定义页面的字段:
public class APageObject {
@FindBy(id="fieldOne_id")
WebElement fieldOne;
@FindBy(xpath="fieldTwo_xpath")
WebElement fieldTwo;
<RESTO OF THE Page IMPLEMENTATION>
}
Run Code Online (Sandbox Code Playgroud)
我想要:
a)页面是一个更通用的容器,能够将多个表单组合在一起.
b)使用普通java对象而不是WebElement接口来声明页面上的字段.
c)有一种简单的方法来确定页面上的元素是否可以使用.
例如:
public class PageObject {
private APageForm formA;
<OTHER FORMS DECLARATIONS >
public void init(final WebDriver driver) {
this.driver = driver;
formA = new APageForm());
PageFactory.initElements(new SomeDecorator(driver), formA);
<OTHER FORMS INITIALIZATION>
}
<THE REST OF the PAGE IMPLEMENTATION>
}
Run Code Online (Sandbox Code Playgroud)
其中APageForm看起来类似于APageObject,但略有不同 - 表单中的每个字段都由专用的java类定义.
public class APageForm {
@FindBy(id="fieldOne_id")
FieldOne fieldOne;
@FindBy(xpath="fieldTwo_xpath")
FieldTwo fieldTwo;
<REST OF THE FORM IMPLEMENTATION>
}
Run Code Online (Sandbox Code Playgroud)
还有两点需要记住:
a)这种方法应该使用Selenium ExpectedCondition;
b)这种方法应该有助于在"数据传递"和"数据断言"之间分离代码.
元件
公共接口元素{
public boolean isVisible();
public void click();
public ExpectedCondition<WebElement> isReady();
Run Code Online (Sandbox Code Playgroud)
}
此接口应扩展为更复杂的元素,如按钮,链接,标签等.例如:
public interface TextField extends Element {
public TextField clear();
public TextField enterText(String text);
public ExpectedCondition<WebElement> isReady();
}
Run Code Online (Sandbox Code Playgroud)
每个元素都应该提供isReady()以避免使用Thread.sleep().
元素的每个实现都应该扩展AbstractElement类:
public abstract class AbstractElement implements Element {
protected WebElement wrappedElement;
protected AbstractElement (final WebElement el) {
this.wrappedElement = el;
}
@Override
public boolean isVisible() {
return wrappedElement.isDisplayed();
}
@Override
public void click() {
wrappedElement.click();
}
public abstract ExpectedCondition<WebElement> isReady();
}
Run Code Online (Sandbox Code Playgroud)
例如:
public class ApplicationTextField extends AbstractElement implements TextField {
public ApplicationTextField(final WebElement el) {
super(el);
}
@Override
public TextField clear() {
wrappedElement.clear();
return this;
}
@Override
public TextField enterText(String text) {
char[] letters = text.toCharArray();
for (char c: letters) {
wrappedElement.sendKeys(Character.toString(c));
// because it is typing too fast...
try {
Thread.sleep(70);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return this;
}
@Override
public ExpectedCondition<WebElement> isReady() {
return ExpectedConditions.elementToBeClickable(wrappedElement);
}
}
Run Code Online (Sandbox Code Playgroud)
以下界面描述了一个元素工厂:
public interface ElementFactory {
public <E extends Element> E create(Class<E> containerClass, WebElement wrappedElement);
}
Run Code Online (Sandbox Code Playgroud)
元素工厂的实现是:
public class DefaultElementFactory implements ElementFactory {
@Override
public <E extends Element> E create(final Class<E> elementClass,
final WebElement wrappedElement) {
E element;
try {
element = findImplementingClass(elementClass)
.getDeclaredConstructor(WebElement.class)
.newInstance(wrappedElement);
}
catch (InstantiationException e) { throw new RuntimeException(e);}
catch (IllegalAccessException e) { throw new RuntimeException(e);}
catch (IllegalArgumentException e) {throw new RuntimeException(e);}
catch (InvocationTargetException e) {throw new RuntimeException(e);}
catch (NoSuchMethodException e) { throw new RuntimeException(e);}
catch (SecurityException e) {throw new RuntimeException(e);}
return element;
}
private <E extends Element> Class<? extends E> findImplementingClass (final Class<E> elementClass) {
String pack = elementClass.getPackage().getName();
String className = elementClass.getSimpleName();
String interfaceClassName = pack+"."+className;
Properties impls = TestingProperties.getTestingProperties().getImplementations();
if (impls == null) throw new RuntimeException("Implementations are not loaded");
String implClassName = impls.getProperty(interfaceClassName);
if (implClassName == null) throw new RuntimeException("No implementation found for interface "+interfaceClassName);
try {
return (Class<? extends E>) Class.forName(implClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to load class for "+implClassName,e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
工厂读取属性文件以使用元素的所需实现:
com.qamation.web.elements.Button = tests.application.elements.ApplicationButton
com.qamation.web.elements.Link = tests.application.elements.ApplicationLink
com.qamation.web.elements.TextField = tests.application.elements.ApplicationTextField
com.qamation.web.elements.Label=tests.application.elements.ApplicationLabel
Run Code Online (Sandbox Code Playgroud)
元素工厂将由FieldDecorator接口的实现使用.我将在下面讨论这个问题.
此时元素的部分覆盖范围已完成.以下是摘要:
每个元素由扩展Element接口的接口描述.
每个元素的实现都扩展了AbstractElement类,并完成了isReady()以及其他必需的方法.
应在属性文件中定义所需元素的实现.
元素工厂将实例化一个元素,并通过装饰器将其传递给PageFactory.initElement().
起初看起来很复杂.
创建和使用简单元素来模拟复杂的表单和页面变得非常方便.
容器是将元素和其他容器保持在一起以便为复杂的Web表单和页面建模的工具.
容器结构类似于元素,但它更简单.
容器由接口定义:
public interface Container {
public void init(WebElement wrappedElement);
public ExpectedCondition<Boolean> isReady(WebDriverWait wait);
}
Run Code Online (Sandbox Code Playgroud)
容器有AbstractContainer基类:
public abstract class AbstractContainer implements Container{
private WebElement wrappedElement;
@Override
public void init(WebElement wrappedElement) {
this.wrappedElement = wrappedElement;
}
public abstract ExpectedCondition<Boolean> isReady(final WebDriverWait wait);
}
Run Code Online (Sandbox Code Playgroud)
注意容器的init方法很重要:method的参数是WebElement接口的一个实例.
与元素类似,容器应该实现isReady()方法.不同之处在于返回类型:ExpectedCondition.
容器的"就绪"状态取决于容器中包含的元素的组合.
使用布尔类型将几个条件组合成一个条件是合乎逻辑的.
以下是容器的示例:
public class LoginContainer extends AbstractContainer{
@FindBy(id="Email")
private TextField username;
@FindBy(id="Passwd" )
private TextField password;
@FindBy(id="signIn")
private Button submitButton;
public void login(final String username, final String password) {
this.username.clear().enterText(username);
this.password.clear().enterText(password);
this.submitButton.press();
}
@Override
public ExpectedCondition<Boolean> isReady(final WebDriverWait wait) {
return new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(final WebDriver driver) {
ExpectedCondition isUserNameFieldReady = username.isReady();
ExpectedCondition isPasswordFieldReady = password.isReady();
ExpectedCondition isSubmitButtonReady = submitButton.isReady();
try {
wait.until(isUserNameFieldReady);
wait.until(isPasswordFieldReady);
wait.until(isSubmitButtonReady);
return new Boolean(true);
}
catch (TimeoutException ex) {
return new Boolean(false);
}
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
容器工厂由接口定义:
public interface ContainerFactory {
public <C extends Container> C create(Class<C> wrappingClass, WebElement wrappedElement);
}
Run Code Online (Sandbox Code Playgroud)
容器工厂的实现比元素工厂简单得多:
public class DefaultContainerFactory implements ContainerFactory {
@Override
public <C extends Container> C create(final Class<C> wrappingClass,
final WebElement wrappedElement) {
C container;
try {
container = wrappingClass.newInstance();
}
catch (InstantiationException e){throw new RuntimeException(e);}
catch (IllegalAccessException e){throw new RuntimeException(e);}
container.init(wrappedElement);
return container;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是容器的简短摘要:
容器用于将元件和其他容器组合成一个单元.
容器的实现应该从AbstructContainer类扩展.它应该实现isReady()和容器所需的其他方法.
容器将被实例化,并由容器工厂通过装饰器传递给PageFactory.initElement().
页面是WebDriver实例和容器之间的桥梁.页面有助于将WebDriver与测试活动,测试数据配置和测试结果验证分离.
页面由接口定义,类似于Container:
public interface Page {
public void init(WebDriver driver);
}
Run Code Online (Sandbox Code Playgroud)
容器和页面之间的区别在于init():
public abstract class AbstractPage implements Page {
protected WebDriver driver;
@Override
public void init(WebDriver driver) {
this.driver = driver;
}
}
Run Code Online (Sandbox Code Playgroud)
Page的init方法将WebDriver实例作为参数.
页面实现应该扩展AbstractPage类.例如,一个简单的gmail页面:
public interface GMailPage extends Page {
public NewEmail startNewEmail();
}
public class DefaultGMailPage extends AbstractPage implements GMailPage {
private LeftMenueContainer leftMenue;
public void init(final WebDriver driver) {
this.driver = driver;
leftMenue = new LeftMenueContainer();
PageFactory.initElements(new DefaultWebDecorator(driver), leftMenue);
WebDriverWait wait = new WebDriverWait(driver,TestingProperties.getTestingProperties().getTimeOutGeneral());
ExpectedCondition<Boolean> isEmailFormReady = leftMenue.isReady(wait);
wait.until(isEmailFormReady);
}
@Override
public NewEmail startNewEmail() {
leftMenue.pressCompose();
NewEmailWindowContainer newEmail = new NewEmailWindowContainer();
PageFactory.initElements(new DefaultWebDecorator(driver), newEmail);
WebDriverWait wait = new WebDriverWait(driver,TestingProperties.getTestingProperties().getTimeOutGeneral());
ExpectedCondition<Boolean> isNewEmailReady=newEmail.isReady(wait);
wait.until(isNewEmailReady);
return newEmail;
}
}
Run Code Online (Sandbox Code Playgroud)
组件摘要:
元素 - > AbstractElement - >元素的实现 - >元素工厂
容器 - > AbstractContainer - >容器工厂
页面 - > AbstractPage.
当PageFactory.initElements()调用提供的装饰器时,上述结构变为活动状态.
基本实现已经存在 - DefaultFieldDecorator.让我们用它.
public class DefaultWebDecorator extends DefaultFieldDecorator {
private ElementFactory elementFactory = new DefaultElementFactory();
private ContainerFactory containerFactory = new DefaultContainerFactory();
public DefaultWebDecorator(SearchContext context) {
super(new DefaultElementLocatorFactory(context));
}
@Override
public Object decorate(ClassLoader classLoader, Field field) {
ElementLocator locator = factory.createLocator(field);
WebElement wrappedElement = proxyForLocator(classLoader, locator);
if (Container.class.isAssignableFrom(field.getType())) {
return decorateContainer(field, wrappedElement);
}
if (Element.class.isAssignableFrom(field.getType())) {
return decorateElement(field, wrappedElement);
}
return super.decorate(classLoader, field);
}
private Object decorateContainer(final Field field, final WebElement wrappedElement) {
Container container = containerFactory.create((Class<? extends Container>)field.getType(), wrappedElement);
PageFactory.initElements(new DefaultWebDecorator(wrappedElement), container);
return container;
}
private Object decorateElement(final Field field, final WebElement wrappedElement) {
Element element = elementFactory.create((Class<? extends Element>)field.getType(), wrappedElement);
return element;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,在初始化所有子元素和容器之前,decorateContainer()不会退出.
现在,让我们看一个简单的测试,它按下gmail页面上的Compose按钮并检查屏幕上是否出现一个新的电子邮件窗口:
public class NewEmailTest {
private WebDriver driver;
@BeforeTest
public void setUp() {
driver = new FirefoxDriver();
driver.manage().window().maximize();
}
@AfterTest
public void tearDown() {
driver.close();
}
@Test (dataProvider = "inputAndOutput", dataProviderClass = com.qamation.data.provider.TestDataProvider.class)
public void startNewEmailTest(DataBlock data) {
DefaultHomePage homePage = new DefaultHomePage();
driver.manage().deleteAllCookies();
driver.get(data.getInput()[0]);
homePage.init(driver);
NewEmail newEmail = homePage.signIn().login(data.getInput()[1], data.getInput()[2]).startNewEmail();
for (String[] sa : data.getExpectedResults()) {
WebElement el = driver.findElement(By.xpath(sa[0]));
Assert.assertTrue(el.isDisplayed());
}
}
}
Run Code Online (Sandbox Code Playgroud)
从Eclipse运行测试时,需要使用以下VM参数:
-DpropertiesFile = testing.properties
有关QA和QA Automation的更多文章可以在http://qamation.blogspot.com找到
| 归档时间: |
|
| 查看次数: |
14105 次 |
| 最近记录: |