@FindBy(xpath="//button[@class='submitButton']")
WebElement submit;
我在使用 POM 的测试框架中使用了这种类型的代码。
我想将这个 Xpath 存储在属性文件中,并且只想为其分配 key 。
例如:
@FindBy(xpath=config.getsubmit())
WebElement submit;
有什么方法可以存储 WebElement 或制作 WebElement 存储库吗?
最佳答案
您不能使用普通的 PageObjects 和 PageFactory 实现这一点。
您需要进行一些自定义,然后才能完成此操作。
要完成此操作,您基本上需要以下内容
org.openqa.selenium.support.pagefactory.ElementLocator
的自定义实现,以便您可以让它兑现对findElement
和findElements
的调用> 使用提供的WebDriver
实例。默认实现只是从注释中查询。org.openqa.selenium.support.pagefactory.ElementLocatorFactory
的自定义实现,以便它可以生成您自定义的ElementLocator
实例,而不是默认实例。- 自定义注释解析器,以便您可以通过扩展
org.openqa.selenium.support.pagefactory.AbstractAnnotations
来解析添加到WebElement
对象的自定义注释 - 最后但并非最不重要的一点是,捕获一些元数据的自定义注释可用于从给定 Web 元素的 JSON 文件中读取定位器
有了这些你可以做以下事情
- 定义您的自定义注释,这样您就可以从文件中唯一地识别定位器。
- 定义一个自定义注释解析器,它将读取自定义注释的属性并构造一个
By
对象 - 定义一个自定义
ElementLocator
,以便它使用自定义注释解析器来查找元素。 - 定义一个自定义
ElementLocatorFactory
,以便它生成自定义ElementLocator
的实例。
我之前曾将整个概念写成博客。请看一下here
要全面了解 PageFactory 的工作原理,请查看 this。我创建的博客。
有人以我的博文为起点并构建了一个库,它也可以为您完成所有这些工作。你可以从这里消费它https://github.com/shchukax/search-with
为了完整起见,我包含了我博客中的所有代码片段
json 看起来像这样
[
{
"pageName": "HomePage",
"name": "abTesting",
"locateUsing": "xpath",
"locator": "//a[contains(@href,'abtest')]"
},
{
"pageName": "HomePage",
"name": "checkBox",
"locateUsing": "xpath",
"locator": "//a[contains(@href,'checkboxes')]"
},
{
"pageName": "CheckboxPage",
"name": "checkBox1",
"locateUsing": "xpath",
"locator": "//input[@type='checkbox'][1]"
},
{
"pageName": "CheckboxPage",
"name": "checkBox2",
"locateUsing": "xpath",
"locator": "//input[@type='checkbox'][2]"
}
]
自定义注释看起来像这样
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.FIELD)
public @interface SearchWith {
String inPage() default "";
String locatorsFile() default "";
String name() default "";
}
自定义ElementLocator
实现
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import java.util.List;
public class FileBasedElementLocator implements ElementLocator {
private final SearchContext searchContext;
private final boolean shouldCache;
private final By by;
private WebElement cachedElement;
private List<WebElement> cachedElementList;
public FileBasedElementLocator(SearchContext searchContext, AbstractAnnotations annotations) {
this.searchContext = searchContext;
this.shouldCache = annotations.isLookupCached();
this.by = annotations.buildBy();
}
@Override
public WebElement findElement() {
if (cachedElement != null && shouldCache) {
return cachedElement;
}
WebElement element = searchContext.findElement(by);
if (shouldCache) {
cachedElement = element;
}
return element;
}
@Override
public List<WebElement> findElements() {
if (cachedElementList != null && shouldCache) {
return cachedElementList;
}
List<WebElement> elements = searchContext.findElements(by);
if (shouldCache) {
cachedElementList = elements;
}
return elements;
}
}
自定义元素定位器工厂如下所示
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
import java.lang.reflect.Field;
public class FileBasedElementLocatorFactory implements ElementLocatorFactory {
private final SearchContext searchContext;
public FileBasedElementLocatorFactory(SearchContext searchContext) {
this.searchContext = searchContext;
}
@Override
public ElementLocator createLocator(Field field) {
return new FileBasedElementLocator(searchContext, new CustomAnnotations(field));
}
}
AbstractAnnotations
的自定义实现
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.openqa.selenium.By;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;
import organized.chaos.annotations.SearchWith;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Iterator;
class CustomAnnotations extends AbstractAnnotations {
private final Field field;
CustomAnnotations(Field field) {
this.field = field;
}
@Override
public By buildBy() {
SearchWith search = field.getAnnotation(SearchWith.class);
Preconditions.checkArgument(search != null, "Failed to locate the annotation @SearchWith");
String elementName = search.name();
String pageName = search.inPage();
String locatorsFile = search.locatorsFile();
Preconditions
.checkArgument(isNotNullAndEmpty(elementName), "Element name is not found.");
Preconditions.checkArgument(isNotNullAndEmpty(pageName), "Page name is missing.");
Preconditions.checkArgument(isNotNullAndEmpty(locatorsFile), "Locators File name not provided");
File file = new File(locatorsFile);
Preconditions.checkArgument(file.exists(), "Unable to locate " + locatorsFile);
try {
JsonArray array = new JsonParser().parse(new FileReader(file)).getAsJsonArray();
Iterator&lt;JsonElement&gt; iterator = array.iterator();
JsonObject foundObject = null;
while (iterator.hasNext()) {
JsonObject object = iterator.next().getAsJsonObject();
if (pageName.equalsIgnoreCase(object.get("pageName").getAsString()) &&
elementName.equalsIgnoreCase(object.get("name").getAsString())) {
foundObject = object;
break;
}
}
Preconditions.checkState(foundObject != null, "No entry found for the page [" + pageName + "] in the "
+ "locators file [" + locatorsFile + "]");
String locateUsing = foundObject.get("locateUsing").getAsString();
if (! ("xpath".equalsIgnoreCase(locateUsing))) {
throw new UnsupportedOperationException("Currently " + locateUsing + " is NOT supported. Only xPaths "
+ "are supported");
}
String locator = foundObject.get("locator").getAsString();
Preconditions.checkArgument(isNotNullAndEmpty(locator), "Locator cannot be null (or) empty.");
return new By.ByXPath(locator);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isLookupCached() {
return (field.getAnnotation(CacheLookup.class) != null);
}
private boolean isNotNullAndEmpty(String arg) {
return ((arg != null) && (! arg.trim().isEmpty()));
}
}
这是页面对象类的样子
import org.openqa.selenium.WebElement;
import organized.chaos.annotations.SearchWith;
public class HomePage {
public static final String PAGE = "HomePage";
@SearchWith (inPage = HomePage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "abTesting")
private WebElement abTestingLink = null;
@SearchWith (inPage = HomePage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox")
private WebElement checkBoxLink = null;
public HomePage() {
}
public CheckBoxPage navigateToCheckBoxPage() {
checkBoxLink.click();
return new CheckBoxPage();
}
}
另一个页面类
import org.openqa.selenium.WebElement;
import organized.chaos.annotations.SearchWith;
public class CheckBoxPage {
private static final String PAGE = "CheckBoxPage";
@SearchWith (inPage = CheckBoxPage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox1")
private WebElement checkBoxOne;
@SearchWith (inPage = CheckBoxPage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox2")
private WebElement checkBoxTwo;
public void unCheckCheckBoxTwo() {
if (checkBoxTwo.isSelected()) {
checkBoxTwo.click();
}
}
public boolean isCheckBoxTwoUnchecked() {
return (! checkBoxTwo.isSelected());
}
}
这是一个使用它的测试类
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import organized.chaos.pages.CheckBoxPage;
import organized.chaos.pages.HomePage;
import organized.chaos.support.FileBasedElementLocatorFactory;
public class AlteredPageFactoryDemo {
private RemoteWebDriver driver;
@BeforeClass
public void setup() {
driver = new ChromeDriver();
}
@AfterClass
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
@Test
public void testMethod() {
driver.get("https://the-internet.herokuapp.com/");
HomePage homePage = new HomePage();
ElementLocatorFactory factory = new FileBasedElementLocatorFactory(driver);
PageFactory.initElements(factory, homePage);
CheckBoxPage checkboxPage = homePage.navigateToCheckBoxPage();
PageFactory.initElements(factory, checkboxPage);
checkboxPage.unCheckCheckBoxTwo();
Assert.assertTrue(checkboxPage.isCheckBoxTwoUnchecked());
}
}
关于java - 如何将 WebElement 存储在 json 或属性中以便我可以轻松更改它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53850655/