如何将WebElement存储在json或属性中,以便可以轻松更改它

时间:2018-12-19 11:52:15

标签: java selenium automated-tests

@FindBy(xpath="//button[@class='submitButton']")
WebElement submit;

我已经在使用POM的测试框架中使用了这类代码。

我想将此Xpath存储在属性文件中,并且只想为其分配密钥。

例如:

@FindBy(xpath=config.getsubmit())
WebElement submit;

有什么方法可以存储WebElement或建立WebElement存储库吗?

4 个答案:

答案 0 :(得分:1)

您不能使用PageObjects和PageFactory的普通香草味来做到这一点。

您需要进行一些自定义,之后才能完成此操作。

要完成此操作,您基本上需要以下内容

  • org.openqa.selenium.support.pagefactory.ElementLocator的自定义实现,以便您可以使用提供的findElement实例来兑现对findElementsWebDriver的调用。默认实现只是从注释中查询。
  • org.openqa.selenium.support.pagefactory.ElementLocatorFactory的自定义实现,以便它可以生成自定义的ElementLocator实例,而不是默认实例。
  • 自定义注释解析器,以便您可以通过扩展WebElement来解析已添加到org.openqa.selenium.support.pagefactory.AbstractAnnotations对象的自定义注释
  • 最后但并非最不重要的是,一个自定义注释捕获了一些元数据,这些元数据可用于从给定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&amp;lt;JsonElement&amp;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());
    }
}

答案 1 :(得分:0)

您不能将值传递给在运行时确定的注释,仅允许使用诸如final字段或类型之类的常量。有关详情,请参见the spec。这是因为注释是在编译时评估的。它们的值可能保留在类文件中。

尽管您可以find elements programmatically

WebElement element = driver.findElement(By.xpath(config.getsubmit()));

但是,这需要您引用WebDriver实例。

答案 2 :(得分:0)

Vicky,

您可以通过使用POJO模型创建来创建WebElement存储库。

Public class WebElementRepo 
{
static WebElement01 = null;

// then create getter setter for all these webelements

public static void setWebElement01(WebElement WE)
{
WebElement01 = WE;
}

public static WebElement getWebElement01(WebElement WE)
{
return WebElement01;
}

}

当您需要将Web元素保存到资源库时,只需将webelement传递给WebElementRepo.setWebElement()并使用WebElementRepo.getWebElement()即可检索该webelement。

答案 3 :(得分:-1)

@FindBy接受final字符串

static final String xpath;
xpath=config.getsubmit(); 
@FindBy(xpath)
WebElement submit;