2

我们正在为一些 Intranet 应用程序实施 Web 测试自动化项目。

为了简化每个测试的编写,我们正在设计一个可以使用不同适配器实现的 Java DSL(到目前为止,我们选择了 Sahi 和 Selenium/WebDriver,因为我们希望在性能、可读性、可维护性等)。

我们在 DSL 中确定了两种类型的操作:

1) Primitive:它的实现肯定要处理 HTML/Selenium/Sahi/etc 的细节。示例:(使用 Sahi 网络驱动程序)

public void insertProjectRecord(String projectName) {
  b.link("Create new project").click();
  b.textbox("ctl00$ProjectForm$Name").setValue(projectName);
  b.span("Insert").click();
}

2) Non-Primitive:出于可重用目的,值得包含在我们的 DSL 中的操作,尽管可以使用原语构建。例子:

public void createFormulation(String projectName, String rteDummyText) {
  goToAddProjectPage();
  insertProjectRecord(projectName);
  switchToEditModeForFirstAvailableRecord();
  editBeneficiaryCountries();
  editAcronyms(rteDummyText);
  saveSectionChanges();
}

问题:我们最初是从一个只有原始操作的接口开始的,但后来我们将其更改为一个抽象类以包含非原始方法(如果需要,允许特定实现覆盖)。但是,将基元和非基元混合起来感觉并不“OK”,而且方法列表肯定会变得很长。

你会建议和/或探索什么其他方法?

4

1 回答 1

2

我强烈推荐使用页面对象模型。在此您为每个页面创建一个类,然后将项目抽象出来。

我在这里写了一篇关于编写可维护测试的博客文章。您可以在此处查看我关于 Page 对象模型的博文

所以你的对象可能如下所示。

public class Home
{
    private readonly ISelenium _selenium;

    /// <summary>
    /// Instantiates a new Home Page object. Pass in the Selenium object created in the test SetUp(). 
    /// When the object in instantiated it will navigate to the root
    /// </summary>
    /// <param name="selenium">Selenium Object created in the tests
    public Home(ISelenium selenium)
    {
        this._selenium = selenium;
        if (!selenium.GetTitle().Contains("home"))
        {
            selenium.Open("/");
        }
    }

    /// <summary>
    /// Navigates to Selenium Tutorials Page. Selenium object wll be passed through
    /// </summary>
    /// <returns>SeleniumTutorials representing the selenium_training.htm</returns>
    public SeleniumTutorials ClickSelenium()
    {
        _selenium.Click("link=selenium");
        _selenium.WaitForPageToLoad("30000");
        return new SeleniumTutorials(_selenium);
    }

    /// <summary>
    /// Click on the blog or blog year and then wait for the page to load
    /// </summary>
    /// <param name="year">blog or blog year
    /// <returns>Object representing /blog.* pages</returns>
    public Blog ClickBlogYear(string year)
    {
        _selenium.Click("link=" + year);
        _selenium.WaitForPageToLoad("30000");
        return new Blog(_selenium);
    }
    // Add more methods as you need them
}

public class SeleniumXPathTutorial
{
    private readonly ISelenium _selenium;

    public const string FirstInput = "number1";
    public const string SecondInput = "number2";
    public const string Total = "total";

    public SeleniumXPathTutorial(ISelenium selenium)
    {
        this._selenium = selenium;
    }

    public bool IsInputOnScreen(string locator)
    {
        return _selenium.IsElementPresent(locator);
    }
}

然后测试类就像

[TestFixture]
public class SiteTests
{
    private ISelenium selenium;
    [SetUp]
    public void Setup()
    {
        selenium = new DefaultSelenium("localhost", 4444, "*chrome", "http://www.theautomatedtester.co.uk");
        selenium.Start();
    }

    [TearDown]
    public void Teardown()
    {
        selenium.Stop();
    }

    [Test]
    public void ShouldLoadHomeThenGoToXpathTutorial()
    {
        Home home = new Home(selenium);
        SeleniumTutorials seleniumTutorials = home.ClickSelenium();
        SeleniumXPathTutorial seleniumXPathTutorial = seleniumTutorials.ClickXpathTutorial();
        Assert.True(seleniumXPathTutorial.
                    IsInputOnScreen(SeleniumXPathTutorial.FirstInput));
        Assert.True(seleniumXPathTutorial
                    .IsInputOnScreen(SeleniumXPathTutorial.SecondInput));
        Assert.True(seleniumXPathTutorial
                    .IsInputOnScreen(SeleniumXPathTutorial.Total));
    }
}
于 2010-08-25T12:36:17.107 回答