2

在过去的一年里,我为我的团队构建了一个非常好的 WebDriver 框架。相当标准的票价:页面类通常在我们的平台上封装页面的全部功能(控件作为对象,根据需要的方法)并使用一些全局方法扩展基类,在 JUnit 测试类中调用多个页面,典型的断言方法,亚达亚达。书本上没有什么奢侈的东西,但非常实用和灵活。

然而,最近,我被要求使用该框架来自动化大量页面,这些页面的表单可以容纳 100 个甚至更多的输入、选择、选项等。这让我感到非常震惊。此外,许多自定义表单控件的 id 会随着环境的变化而变化(幸运的是,在初始推送后它们在每个环境中保持静态)。反正...

让我们看一下我每天使用的典型 PageObject 结构:

/** Constructor*/
public someConstructor(WebDriver driver){
   super(driver, pageTitle);
}

/**Locators*/
By searchBoxLocator = By.id("phSearchInput");
By searchBoxClearLocator = By.id("phSearchClearButton");
By searchButtonLocator = By.cssSelector("input[value='Search']");


/**Some Methods*/
public void selectFromTabBar(String tabName){
   driver.findElement(By.linkText(tabName)).click();
}

public static void enterInputValue(WebDriver driver, By by, String val){

   List<WebElement> elements = null;
   elements = driver.findElements(by);

   if(!elements.isEmpty()){
     driver.findElement(by)).sendKeys(val);     
   }else{
     throw new NoSuchElementException("Message");
   }
}

就像我提到的,这里没有什么异国情调,但现在我要向大家提问。假设我没有传统的 5-15 By's per PageObject,但可能需要超过 100 个页面来处理 10 个页面。更复杂的是,它们在每个环境中也将具有独特的价值,这完全不在每个人的控制范围内,无法调和。那么这里的适当方法是什么......我是否咬紧牙关并硬编码每页 100 英寸作者,我是否将所有作者外部化为,比如说,一个 Excel 文档并通过我不知道,JXL 或其他方式拉入所有内容,或者我是否对我知道将是静态的 By 进行硬编码并将所有内容都放入外部文件中?

归根结底,我知道没有正确的答案,但我只是好奇其他人对此的态度。现在,我已经为具有如此多表单元素的页面外部化了 By,并定义了不会在 PageObject 中更改的控件,但感觉很笨重。也许我追求的优雅太多了,但任何想法都会非常棒。

4

1 回答 1

3

这主要是基于意见但有趣的问题。

我的建议是模块化您的页面。

例如,您有一个包含 100 个定位器的页面,但它们肯定不可能是 100 个相似的文本框来让用户填写。(如果是这样,这里的解决方案可能是首先重新设计您的 UI)

如果这 100 个元素属于不同的组件,例如顶部工具栏中的 20 个元素、列表视图中的 20 个元素、表单中的 20 个元素和底部工具栏中的 20 个元素。然后,您可能希望为每个组件创建不同的类。

例如,这里是一个普通的页面对象。

public class FooPage {

    private IWebDriver driver;

    public FooPage(IWebDriver driver) {
         this.driver = driver;
    }

    public IWebElement Element1 {
         get { return driver.FindElement(By.CssSelector(".something1")); }
    }

    // ...
    public IWebElement Element100 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void AddItem(){
    }

    public void ClearList(){
    }
}

您可以将这些元素分成不同的组件,例如 、FooPageTopToolbarFooPageList

public class FooPageTopToolbar {

    private IWebDriver driver;

    public FooPageTopToolbar(IWebDriver driver) {
         this.driver = driver;
    }

    // ...
    public IWebElement ToolbarElement10 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void AddItem(){
    }
}

public class FooPageList {

    private IWebDriver driver;

    public FooPageList(IWebDriver driver) {
         this.driver = driver;
    }

    // ...
    public IWebElement ListElement10 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void ClearList(){
    }
}

现在你的FooPage会看起来像

public class FooPage {

    private IWebDriver driver;

    public FooPage(IWebDriver driver) {
         this.driver = driver;
    }

    public FooPageTopToolbar {
         get { return new FooPageTopToolbar(driver); }
    }

    // other components as well
    public FooPageList {
         get { return new FooPageList(driver); }
    }
}

请注意,这只是一个演示,您还可以考虑获取继承接口抽象来构建您的页面对象。例如,如果TopToolbar由许多其他页面共享,那么您只需要一个类。如果不同的页面具有相似但略有不同的工具栏,则创建某种抽象工具栏类。

另外,您提到您针对不同的环境有不同的定位器,我认为最好的解决方案是将元素标识符添加到您的源代码中(通过“标识符”,我的意思是任何可识别的部分,可能是 HTML id,但最常见的是唯一class用于测试目的)。在这种情况下,您只需要一组 UI 开发人员不经常更改的测试定位器。

于 2014-01-20T03:48:08.070 回答