【问题标题】:How can I store WebElement in json or property so that I can change it easily如何将 WebElement 存储在 json 或属性中以便我可以轻松更改它
【发布时间】:2019-05-19 21:52:28
【问题描述】:
@FindBy(xpath="//button[@class='submitButton']")
WebElement submit;

我在使用 POM 的测试框架中使用过这种类型的代码。

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

例如:

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

有没有办法存储 WebElement 或制作 WebElement 存储库?

【问题讨论】:

    标签: java selenium automated-tests


    【解决方案1】:

    @FindBy 接受 final 字符串

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

    【讨论】:

    • 不,我仍然收到错误,这不适用于 FindBy
    • 注解的值必须是静态表达式。 config.getsubmit() 不是静态的。
    【解决方案2】:

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

    虽然你可以find elements programmatically:

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

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

    【讨论】:

      【解决方案3】:

      您无法使用 PageObjects 和 PageFactory 的普通风味来做到这一点。

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

      要完成这项工作,您基本上需要以下内容

      • org.openqa.selenium.support.pagefactory.ElementLocator 的自定义实现,以便您可以使用提供的WebDriver 实例调用findElement 和findElements。默认实现只是从注解中查询。
      • 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

      为了完整起见,我将我博客中的所有代码 sn-ps 包括在内

      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());
          }
      }
      

      【讨论】:

        【解决方案4】:

        维姬,

        您可以通过使用 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。

        【讨论】:

        • 是的,但是在这里我已经创建了一个页面对象模型,但是我需要将元素存储在配置文件中,以便如果元素发生更改,我可以在配置文件中进行更改。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-08
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        • 2015-05-19
        • 1970-01-01
        相关资源
        最近更新 更多