全堆栈测试自动化框架的5个必备特性—第2部分


在一个last articles从这个系列中,我们谈到了现代测试自动化框架应该能够解决的大量问题。Full-stack test automation frameworks是最新的第五代工具。他们有一些特点,使他们比前几代人更好。允许你在新出现的复杂环境中使用它们。在5 Must-Have Features of Full-Stack Test Automation Frameworks — Part 1,我们讨论了这种框架应该具备的前五个特性。其中一些是跨平台、跨技术和云就绪。故障排除简单性、库定制和简单的知识转移。在这里,我将扩展列表并添加一个新的类别——应用编程接口可用性。此外,提到的一些功能解决了“Automated Tests Are Not Stable“问题。

应用编程接口可用性——定位元素

普通网络驱动程序示例

香草代表只使用标准网络驱动程序代码而不使用其他任何东西的例子。看看这个标准的WebDriver自动化测试。

[TestMethod]
public void OpenBellatrixDemoPromotions()
{
    IWebDriver driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
    var promotionsLink = driver.FindElement(By.Id("Promotions"));
    promotionsLink.Click();
    Console.WriteLine(promotionsLink.TagName);
}

总的来说,这很好。然而,对我来说,至少在C#中使用FindElement语法需要额外的努力。这是不流畅的,因为你必须开始一个新的“链”使用静态类。此外,由于By包含静态方法,因此您只能使用内置的定位器。这意味着如果促销标识更难看,比如-SF _ col sout-SF _ 1 col _ 1 _ 100-促销。您需要一个定位器,如- By.IdEndingWith

另外,假设您想等待按钮在被点击后消失。使用网络驱动程序是可行的。您可以使用如下代码。

[TestMethod]
public void OpenBellatrixDemoPromotions()
{
    IWebDriver driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
    var promotionsLink = driver.FindElement(By.Id("Promotions"));
    promotionsLink.Click();
    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
    wait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.Id("Promotions")));
    Console.WriteLine(promotionsLink.TagName);
}

我相信你已经注意到了代码的重复。标识(“促销”),这是不好的,因为如果定位器在未来发生变化,我们将不得不多次修复它。发生这种情况是因为在元素被定位之后,IWebElement接口没有给我们一个访问By类的方法,这是一个可用性问题。此外,在我看来,网络驱动的完整用法相当复杂。它可以变得更加简单和方便。

注意:请记住,我描述的所有比较和“问题”并不意味着我不喜欢网络驱动程序库和工具。相反,这是我最喜欢的自动化工具。正如它写在SeleniumHQ 主页:“硒自动化浏览器。”因为人们以无数的方式使用它,所以它被创造成通用的。它的用途之一是自动化测试。它不是测试自动化框架,所以在某些用例中,错过一些特性或者它的应用编程接口不能提供最大的可用性是完全正常的。

改进示例

下面是相同的测试,使用Bellatrix Test Automation Framework

[TestMethod]
public void OpenBellatrixDemoPromotions()
{
    App.NavigationService.Navigate("http://demos.bellatrix.solutions/");
    var promotionsLink = App.ElementCreateService.CreateByLinkText<Anchor>("Promotions");
    promotionsLink.Click();

    Console.WriteLine(promotionsLink.By.Value);
    Console.WriteLine(promotionsLink.WrappedElement.TagName);
}

第一个明显的区别是我们如何定位元素。我们使用创建方法,而不是使用更难键入且不可扩展的“按”语法。一切都遵循最大程度地利用智能感知的自然写作流程。此外,您可以使用自动生成代码code snippets

Bellatrix Element Creation Fluent Interface


贝拉特里克斯包含所有常用定位器的CreateBy方法。最酷的事情之一是贝拉特里克斯元素包含了属性(知道它的位置)。

如果我们需要等待按钮被禁用,我们可以使用下面的代码。

[TestMethod]
public void OpenBellatrixDemoPromotions()
{
    App.NavigationService.Navigate("http://demos.bellatrix.solutions/");
    var promotionsLink = App.ElementCreateService.CreateById<Button>("Promotions");
    promotionsLink.Click();

    promotionsLink.EnsureIsNotVisible();
}

如您所见,由于内置的“按”属性,代码复制被跳过。此外,语法被简化到最低限度。确保方法会自动等待,直到按钮被禁用。

Documentation

应用编程接口可用性——等待元素

普通网络驱动程序示例

用普通的网络驱动程序等待条件是相对复杂的。也许“复杂”不是最准确的词,但是你肯定需要额外的类/方法来跳过代码复制。如前所述,由于您无法访问网络驱动程序元素的位置,您需要在多个位置指定它,或者想出一种重用“按定位器”的方法。

[TestMethod]
public void OpenBellatrixDemoPromotions()
{
    IWebDriver driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
    var promotionsLink = driver.FindElement(By.Id("Promotions"));

    promotionsLink.Click();

    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
    wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("Promotions")));
}

等待应用编程接口还有一个可用性问题。您可以看到所有的ExpectedConditions静态方法,没有根据元素的类型进行筛选。检查下面的例子。元素选择只对组合框或选择元素有意义。

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.ElementToBeSelected(By.Id("Promotions")));

上面,我们传递了按钮的定位符,但是我们可以使用元素被选择的方法。

还有一点,用法是不同的,取决于你使用的方法。

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));  
wait.Until(ExpectedConditions.TextToBePresentInElement(promotionsLink, "Bellatrix"));

该方法接受IWebElement,而不是按定位器。在我看来,这些差异使得整个用法更加混乱和复杂,最终减缓了测试的发展。

WebDriver Wait IntelliSense

不仅方法没有根据元素的类型进行过滤,而且你可以在这里看到各种各样的方法——与标题、网址和框架相关的方法,这更加污染了应用编程接口,当你找到正确的方法时,会导致更长的周期。

改进示例

我们是如何解决这些问题的Bellatrix?您已经看到了一个例子,说明我们是如何等待页面上不存在的元素的。但是我们走得更远。为了使应用编程接口最方便,保证某些条件方法是元素应用编程接口的一部分。此外,您将只看到基于其类型的元素的相关方法。例如,对于锚元素,您不会看到EnsureIsDisabled方法,因为HTML锚元素没有禁用的属性。

Ensure Methods Button Bellatrix

所有元素的用法都是相同的,因为您不必再次指定定位器。

var promotionsLink = App.ElementCreateService.CreateByLinkText<Button>("Promotions");
promotionsLink.Click();
promotionsLink.EnsureIsDisabled();

Documentation

自动处理所有同步问题

另一个 frequent problem人们面临的问题与页面上仍然没有的元素或者不满足某些条件有关。通常,所有这些问题都可以完全用网络驱动程序代码来处理,但是它会根据您试图解决的困难而变化。如果您没有以正确的方式配置库,您可能会使您的测试明显变慢。

隐式等待与显式等待

处理同步问题的一种方法是通过全局隐式等待超时。

IWebDriver driver = new ChromeDriver();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);

但是,在某些情况下,您可能需要更长的等待时间间隔。如果发生这种情况,你会怎么做?一种选择是增加全局超时,但这将影响所有现有的测试。另一个选择是混合隐式和显式等待(如前面的例子所示)。但这是不推荐的。

这是吉姆·埃文斯(核心硒贡献者之一)的一句话,为什么不推荐这样做。

"当你试图混合隐式和显式等待时,你已经误入了“未定义的行为”。您也许能够弄清楚这种行为的规则是什么,但是它们会随着驱动程序的实现细节的改变而改变。所以别这么做。"

"不要混淆隐式和显式等待。问题的一部分在于隐式等待经常发生(但不总是如此!)在WebDriver系统的“远程”端实现。这意味着它们被“烤”到了chromedriver.exe的IEDriverServer.exe,安装在匿名火狐配置文件中的网络驱动火狐扩展,以及Java远程网络驱动服务器。显式等待只在“本地”语言绑定中实现。使用远程网络驱动程序时,事情会变得复杂得多,因为您可能会多次使用系统的本地端和远程端。"

Full Stack Overflow Thread

在使用第一个元素之前等待条件

在大多数测试中,在你使用一些元素点击或者输入文本之前,你需要它是可见的并且存在于网页上。然而,它需要是可点击的或可选择的。这意味着您不仅需要使用网络驱动程序进行断言/验证,还需要在执行操作之前使用它。

这里有一个简单的例子,我们在第一次使用之前等待元素存在。

IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
var promotionsLink = wait.Until(ExpectedConditions.ElementExists(By.Id("Promotions")));

promotionsLink.Click();

然而,假设我们需要我们的元素满足两个以上的条件——存在和可点击。很快你就会意识到没有简单的方法可以做到这一点。你可以写这样的东西。

IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
var promotionsLocator = By.Id("Promotions");
wait.Until(ExpectedConditions.ElementExists(promotionsLocator));
var promotionsLink = wait.Until(ExpectedConditions.ElementToBeClickable(promotionsLocator));

promotionsLink.Click();

打开ExpectedConditions source code—查看这两种方法是如何工作的,并将它们组合到您的匿名函数或普通函数中。但是相信我,你最终会得到更复杂的代码。此外,为您可能需要的每一对或每三对条件创建这样的函数是不合理的。

改进示例

我们是如何决定处理这些问题的Bellatrix?首先,在使用之前,所有元素都在内部等待存在。这解决了所有用例的80%。在此之后,作为创建者应用编程接口的一部分,我们添加了额外的条件方法,您可以链接这些方法。这意味着您可以为每个元素指定无限数量的条件,这些条件需要在元素返回之前满足。

var promotionsLink = App.ElementCreateService.CreateByLinkText<Button>("Promotions").ToBeVisible().ToBeClickable().ToExists();
promotionsLink.Click();
promotionsLink.EnsureIsDisabled();


不同的超时问题

但这不是一切。如果您使用单个WebDriverWait实例,这意味着您使用的每个“直到”方法和条件的超时都是相同的。但这可能因您使用的每种条件和这些条件的每种用法而异。例如,在我的测试中,我希望“可见”的超时时间是15秒,而“不可见”的超时时间是30秒。接下来,对于一些优化的网页,我可能希望将“可见”超时设置为10秒,而不是15秒。在普通的网络驱动程序中,这种灵活性是缺失的,你需要用定制的代码来处理它。

这是一个简单的网络驱动程序问题的简单解决方案。

IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://demos.bellatrix.solutions/");
var wait15Seconds = new WebDriverWait(driver, TimeSpan.FromSeconds(15));
var wait30Seconds = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
var wait45Seconds = new WebDriverWait(driver, TimeSpan.FromSeconds(45));
var promotionsLocator = By.Id("Promotions");
wait15Seconds.Until(ExpectedConditions.ElementExists(promotionsLocator)); // same 30 seconds
var promotionsLink = wait30Seconds.Until(ExpectedConditions.ElementToBeClickable(promotionsLocator));

promotionsLink.Click();

我们有多个不同超时的网络驱动程序。

不同的超时解决方案

Bellatrix,我们有一个JSON配置,在这里我们可以微调框架的不同方面。有一个专门的部分叫做超时设置,您可以在这里更改不同等待条件的默认超时。

"timeoutSettings": {
    "waitForAjaxTimeout": "30",
    "sleepInterval": "1",
    "elementToBeVisibleTimeout": "30",
    "elementToExistTimeout": "30",
    "elementToNotExistTimeout": "30",
    "elementToBeClickableTimeout": "30",
    "elementNotToBeVisibleTimeout": "30",
    "elementToHaveContentTimeout": "15"
},

但是您也可以直接在方法中进一步重写这些值。下面,我们将可视超时设置为30秒,睡眠间隔= 2秒时可点击20秒,睡眠间隔= 1秒时可视超时= 10秒。

var promotionsLink = App.ElementCreateService.CreateByLinkText<Button>("Promotions").ToBeVisible(30).ToBeClickable(20, 2).ToExists(10, 1);
promotionsLink.Click();
promotionsLink.EnsureIsDisabled();


Documentation


摘要


Full-stack test automation frameworks有许多功能可以让您在新出现的复杂环境中工作。在这里,我们主要讨论了测试自动化框架的可用性——定位和等待元素。在本系列的下一篇文章中,我们将讨论如何创建额外的定位器,更快地生成元素,以及为什么您应该关心这些。