2016-12-16 37 views
0

我有一个测试套件,当前可以在不同的开发环境中运行。最近完成了应用程序的部分重写,部署到新环境中执行&。处理具有类似页面逻辑但定位器不同的环境

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

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

遵循这个策略会让我臃肿的页面对象类充满重复的定位器。有没有建议的最佳实践或清洁解决方案来解决这个问题?

可能的解决办法我能想到的是:

  1. 为每个环境创建独立的定位文件,并从页面对象类中删除。
  2. 在当前页面中的对象类
  3. 创建重复或类似名称的定位器为新环境

能anyody对这些解决方案是否OK音响评论创建单独的页面对象?或者提供其他建议?

+0

您在PageObject类中使用了“FindBy”注释吗?或者你使用代码中的findElement? – Grasshopper

+0

我使用@FindBy注释 – Cathal

回答

3

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

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

这就是你将需要包含在FindBy和定位器中发送到findElement() - 使用= 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();    
    } 
} 
+0

嘿草蜢,感谢您的建议。我认为你的建议是正确的。最佳的解决方案可能涉及到创建一个自定义的ElementLoactorFactory,它不是我完全理解如何完成的东西。我最终完全重写了页面对象,因为页面逻辑的差异比我原先想象的要大。但是,现在我剩下相当数量的重复代码 – Cathal

+0

编写自己的自定义代码不是一项主要任务,因为它只是将Selenium代码中的默认类进行了扩展。我想你还需要为自定义的FindBy类添加一个新的参数来扩展现有的参数。否则它会搞乱现有的“使用”一个。如果你有一个不断增长的项目,那么将你重复的代码提取到一个基类或其他策略中,相当肯定它会在稍后的阶段出现并重复你。 – Grasshopper

0

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

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

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

在A和B的HomePage中可以说 有一个带有不同定位符的文本框。

所以在财产文件中的我们可以提到元素 HomePage_Name_TextBox = id_NameInA “id_NameInA”是定位符值,“HomePage_Name_TextBox”是你要用来指特定元素的字符串。

像属性文件聪明的,我们可以提到同样的元素 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. 可以声明一个参数化的构造,并通过在那里你已初始化首页的对象(在主课前阅读所有元素的地图对象可以读取匹配的元素属性文件并通过地图包含所有元素到主页的构造函数)
  2. 或者你可以在HomePage构造函数中读取一个公共属性文件,你可以在其中提到元素属性文件路径。 例如:CommonConfig.properties 此文件可以包含所有配置详细信息,例如在哪个环境中运行脚本,以及要读取的常用文件路径(例如元素文件路径的位置)以及此文件将在构造函数中读取 配置文件看起来像这样
    ElementPropFilePath =资源/ Elements_A.properties

当你想运行在一个脚本,可以在共同财产文件更改“ElementPropFilePath”到“资源/ Elements_A.properties “在跑步之前。 当您想在B中运行脚本时,可以在运行之前(这是机器中文件的位置),将公共属性文件中的“ElementPropFilePath”更改为“Resources/Elements_B.properties”。

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