处理具有类似页面逻辑但位置不同的环境

时间:2016-12-16 12:06:40

标签: java selenium selenium-webdriver pageobjects

我有一个目前在不同开发环境中运行的测试套件。最近完成了对应用程序的完全重写。部署到新环境。

该应用程序看起来&行为几乎相同。页面逻辑或多或少相同。最重要的区别是HTML重写使我的定位器无用。我不确定如何处理这个新环境的定位器,同时坚持页面对象模型。

页面对象模型声明所有页面逻辑应保存在相应的页面对象类中。我假设这也包括定位器。

遵循这个策略会让我看到一个充满重复定位器的膨胀页面对象类。是否有任何建议的最佳实践或清洁解决方案来解决这个问题?

我能想到的可能解决方案是:

  1. 为每个环境创建单独的定位器文件,并将其从页面对象类中删除。
  2. 在当前页面对象类中创建重复或类似命名的定位器
  3. 为新环境创建单独的页面对象
  4. 可以评论这些解决方案听起来不错吗?或提供任何其他建议?

2 个答案:

答案 0 :(得分:3)

肯定会将pageobject类之外的定位器移动到两个不同的类中,一个用于旧定位器,另一个用于新定位器。对每个定位器使用public static final String。您将遇到的问题是Java注释值需要常量表达式,因此您不能使用方法将不同的定位器发送到FindBy。但是您可以使用三元运算符来创建常量表达式。

下面我添加了基于全局标志的代码,单击来自单个WebElement的不同按钮,但定位器由FindBy注释的“using”值上的表达式更改。从属性文件初始化驱动程序时,可以在启动时设置全局标志的值。

这是您需要包含在发现给findElement()的FindBy和定位器中的内容 - using = GlobalFlag.devEnv? NewLocators.newLocxpath:OldLocators.newLocxpath 。在任何地方复制粘贴都会很痛苦。

您可以在网站公开的情况下试用代码。

class CartConstant {
    //Old locators
    public static final String cartxpath = "//span[.='Cart']";
}

class AccountConstant {
    //New locators
    public static final String accxpath = "//span[.='Account']";
}

class GlobalFlag {
    //Initialize this at the start
    public static final boolean devEnv = true;
}

public class ChangeAnnotation {
    //Change this in the code to include the choice
    @FindBy(how=How.XPATH, using=GlobalFlag.devEnv ? AccountConstant.accxpath : CartConstant.cartxpath)
    private WebElement butt;

    @Test
    public void demoSQA() throws InterruptedException {

        System.setProperty("webdriver.chrome.driver", "E:/Software Testing/Selenium/Jars/chromedriver.exe");
        ChromeOptions chop =  new ChromeOptions();
        chop.addArguments("test-type");
        chop.addArguments("start-maximized");
        WebDriver driver = new ChromeDriver(chop);

        driver.get("http://store.demoqa.com/products-page/product-category/imacs/");        
        Thread.sleep(3000);     
        PageFactory.initElements(driver, this);     
        butt.click();               
    }
}

答案 1 :(得分:0)

这就是我设法克服这个问题的方法。

我为不同的环境保留了不同的元素属性文件。

让我们说环境A,B 在我的项目中,我保留了两个名为Elements_A.properties和Elements_B.properties的属性文件 这些属性文件包含所有页面元素。 如果一个元素与另一个元素不同,则不会出现问题,因为根据环境运行脚本时,您可以在脚本中引用相关的属性文件。

让我们说 在HomePage的A和B中,有一个带有不同定位器的文本框。

所以在属性文件A中我们可以提到元素为 HomePage_Name_TextBox = id_NameInA “id_NameInA”是定位符值,“HomePage_Name_TextBox”是您将用于引用该特定元素的字符串。

在属性文件A中,我们可以提及相同的元素 HomePage_Name_TextBox = id_NameInB “id_NameInB”是定位符值,“HomePage_Name_TextBox”是您将用于引用该特定元素的字符串。

您可以注意到两个元素的名称相同( HomePage_Name_TextBox ),定位器值不同。

在每个页面类中,我都声明了一个Map,现在您有几个选项可以决定如何初始化页面的元素。

public class HomePage {

   Map<String, String> elementsMap = new HashMap<String, String>();

   //Option 1
   public HomePage(Map<String, String> elementMapObj) {
      elementsMap = elementMapObj;
   }

   //Option 2
   public HomePage() {
        Properties              prop        = new Properties();
        FileReader              reader;
        HashMap<String, String> propertyMap = new HashMap<String, String>();

        try {
            reader = new FileReader(new File("CommonConfig.properties"));
            prop.load(reader);
            for (String key : prop.stringPropertyNames()) 
            {
                String value        = prop.getProperty(key);
                propertyMap.put(key, value);
            }
        } catch (Exception e) {
            //System.out.println(e.toString());
        }

        try {
            reader = new FileReader(new File(propertyMap.get("ElementPropFilePath")));
            prop.load(reader);
            for (String key : prop.stringPropertyNames()) 
            {
                String value        = prop.getProperty(key);
                elementsMap.put(key, value);
            }
        } catch (Exception e) {
             //System.out.println(e.toString());
        }

   }
}
  1. 您可以声明一个参数化构造函数,并在初始化HomePage对象之前传递一个映射对象,在该对象中读取所有元素(在主类中,您可以读取匹配元素属性文件并将包含所有元素的映射传递给主页的构造函数)
  2. 或者您可以在HomePage构造函数本身中读取公共属性文件,您可以在其中提及Elements属性文件路径。 例如:CommonConfig.properties 此文件可以包含所有配置详细信息,例如您在哪个环境中运行脚本,以及要读取的公共文件路径(例如元素文件路径的位置)以及将在构造函数中读取此文件 配置文件看起来像这样 ElementPropFilePath = Resources / Elements_A.properties
  3. 如果要在A中运行脚本,可以在运行之前将公共属性文件中的“ElementPropFilePath”更改为“Resources / Elements_A.properties”。 如果要在B中运行脚本,可以在运行之前将公共属性文件中的“ElementPropFilePath”更改为“Resources / Elements_B.properties”(这是文件在计算机中的位置)。

    简单地说,如果您维护包含每个环境的所有元素的属性文件,并提供该属性详细信息并填充您在每个页面类中的elementMap,那么您将能够使用公共字符串引用该元素您用于两个环境(在此示例中为HomePage_Name_TextBox)