文本

自定义测试自动化框架:定义特性第2部分

在新构建自定义自动化框架系列中,我们将研究创建自定义测试自动化框架的详细说明。很多刚开始工作的人都有这个特殊的任务,所以我认为理解如何正确地遵循所有高质量的标准和实践是至关重要的。我不喜欢重新发明轮子,所以我鼓励您利用其他经过验证的开源解决方案,如果它们可以被使用并且符合您的需要,而不是编写自己的解决方案。充分利用该领域经证明的专家的知识和专长。如果您遵循这个建议,本系列将再次对您非常有用,因为您将理解测试自动化框架是如何设计、编写和维护的,以及如何在内部工作。关于这个主题的信息对于您选择正确的测试工具是非常宝贵的。如果您决定从头开始,那么本系列对您可能更有用。

我们将逐条讨论自定义测试自动化框架的不同方面和特性。在课程的最后,我们将有一个成熟的自定义测试自动化框架。本系列的第一篇文章将与其说谈论代码,而是如何定义我们所需要的(我们的要求),如何正确地做研究,找到合适的工具,我们将基础框架,最后,为我们的解决方案创建一个详细清单所需的特征分组所有的各种特性,我们将在未来的文章中构建。在课程中,我将使用我们的开源BELLATRIX测试自动化框架作为演示/例子,我相信这是功能最丰富的开源框架之一。

在“自定义测试自动化框架:定义需求和特征”系列的第一篇文章中,我们定义了未来框架的需求和质量/特征。本文将继续更精确地定义根据前面描述的特征分组的各种特性。它们将帮助我们对框架上的工作进行优先排序和规划。我们已经在第1部分中研究了一些特性。现在我们将进一步扩大名单。

5.轻松的知识转移功能

从安装到最复杂的功能,您的团队需要了解的所有内容。 除了带有示例的综合文档之外,我们还可以使用入门工具包演示项目。 此外,它还与直观的API设计相关。

入门套件

团队经常遇到的问题是,帮助/教导新成员如何使用团队的框架编写“适当的”测试。 通常,最高级的人之一在此过程上花费了无数的时间。 入门套件是一种自动化的方法,允许新人们自己学习。 这些项目都有示例,这些示例说明了如何编写测试以及为什么我们不使用特定方法。

我们将研究如何为我们的新定制框架创建此类入门工具包。 他们将通过详细的实际示例来说明框架的功能。 此外,它们还将包含每个部分的详细注释。 在每一章之后,他们将提供人们可以做的练习,这将使它们成为自学的理想选择。 不同的功能将分组在单独的文件夹中,并且在每一章的末尾将有一个包含练习的TODO文件。

丰富的文档

丰富的文档对于任何开源项目的成功都是至关重要的。 我将引导您使用称为GitHub Page的流行免费平台创建和托管此类文档。

6.高度可扩展的功能

每个框架的核心特征之一可能是其扩展和定制能力,以适应不同团队的需求,并可以在各种情况下使用。

扩展测试执行生命周期和插件

所有的测试框架都允许您在测试之前或之后的特定时间执行逻辑。通常测试放在测试类中。MSTest和NUnit的标准测试流程为:

1.执行程序集初始化—对整个项目执行一次

2.对测试类执行类Initialize—一次

3.执行测试初始化——在每次测试之前执行

4.执行测试

5.执行测试清理——在每个测试之后执行

6.执行类清理—对测试类执行一次

7.执行程序集清理—对整个项目执行一次

为什么需要扩展标准工作流?

通常,您希望使用这些主要方法来执行与业务测试相关的逻辑。样本用例:

获取测试失败的屏幕截图

拍摄测试失败的视频

如果在一定时间内未执行,则测试失败

在第三方系统中记录测试结果

控制浏览器的生命周期

我们的框架应该带有一个扩展的测试执行生命周期,以满足这些需求并支持定制的插件。当我们编写插件时,我们应该在新生命周期的不同阶段执行逻辑——TestInitialize之前、TestInitialize之后、TestCleanup之前、TestCleanup之后等等。对于每个测试,应该执行所有注册的插件逻辑。


public class ExecutionTimeUnderTestWorkflowPlugin : TestWorkflowPlugin
{
    protected override void PostTestInit(object sender, TestWorkflowPluginEventArgs e)
    {
        // get the start time
    }
    protected override void PostTestCleanup(object sender, TestWorkflowPluginEventArgs e)
    {
        // total time = start time - current time
        // IF total time > specified time ===> FAIL TEST
    }
}

在PostTestInit中,我们启动了一个秒表。我们在PostTestCleanup方法中获得放置在属性中的数字。然后停止秒表,比较实际时间和指定时间。万一一开始花的时间长,我们考试就不及格。

覆盖全局元素操作

例如,使用JavaScript来单击按钮,而不是使用我们的按钮单击方法。如果我们想要改变所有测试的这种行为,每个框架的UI组件应该给我们这种可能性。我们将需要初始化元素静态委托——全局覆盖{MethodName}。

[AssemblyInitialize]
public static void AssemblyInitialize(TestContext testContext)
{
    Button.OverrideClickGlobally = (e) =>
    {
        e.ToExists().ToBeClickable().WaitToBe();
        App.JavaScriptService.Execute("arguments[0].click();", e);
    };
}

局部覆盖元素操作

这对于仅对默认行为未按预期工作的特定页面进行临时修复可能很有用。我们需要在本地初始化静态委托——Override{MethodName}。

Anchor.OverrideFocusLocally = (e) =>
{
    App.JavaScriptService.Execute("window.focus();");
    App.JavaScriptService.Execute("arguments[0].focus();", anchor);
};

元素行动钩子

扩展框架的另一种方法是使用控件的钩子。每个控件的方法都有两个钩子——一个叫做“动作之前”,另一个叫做“动作之后”。例如,可用的按钮挂钩有:

单击—在单击按钮之前执行的事件

单击—单击按钮后执行的事件

悬停-在按钮悬停之前执行的事件

悬停-在按钮悬停后执行的事件

聚焦-在按钮聚焦之前执行的事件

焦点-在按钮被焦点后执行的事件

用户将需要为这些事件实现事件处理程序并订阅它们。

public void ClickingEventHandler(object sender, ElementActionEventArgs arg)
{
    Logger.LogInformation($"Click {arg.Element.ElementName}");
}
public void HoveringEventHandler(object sender, ElementActionEventArgs arg)
{
    Logger.LogInformation($"Hover {arg.Element.ElementName}");
}

公共服务行动挂钩

扩展框架的另一种方法是将钩子用于其公共服务。 这是我们可以添加的一些常见服务事件的列表:NavigationService – UrlNotNavigatedEvent,如果WaitForPartialUrl引发异常则调用ElementWaitService – OnElementNotFulfillingWaitConditionEvent,如果Wait方法引发异常则调用。

public static void OnElementNotFound(object sender, ExceptionEventArgs args)
{
    var exceptionAnalyser = new ExceptionAnalyser();
    exceptionAnalyser.Analyse(args.Exception);
    throw args.Exception;
}

扩展现有的UI组件

扩展现有元素的一种方法是为其他操作创建扩展方法。


public static class ButtonExtensions
{
    public static void SubmitButtonWithEnter(this Button button)
    {
        var action = new Actions(button.WrappedDriver);
        action.MoveToElement(button.WrappedElement).SendKeys(Keys.Enter).Perform();
    }

扩展现有元素的第二种方法是创建一个子元素。 我们将必须继承要扩展的UI组件。

public class ExtendedButton : Button { public void SubmitButtonWithEnter() { var action = new Actions(WrappedDriver); action.MoveToElement(WrappedElement).SendKeys(Keys.Enter).Perform(); } } 扩展公共服务

我们可以添加向框架的公共服务添加新方法的功能,例如,一种新的特殊导航方式或用于处理对话框警报的自定义逻辑。

注意:通用服务是我们将构建的特殊类,它将IWebDriver接口拆分为更专门的单元,负责各种任务,例如使用Cookie,处理警报,查找元素,浏览器操作等。

要扩展公共服务,我们将需要创建扩展方法以采取其他措施。

public static class NavigationServiceExtensions
{
    public static void NavigateViaJavaScript(this NavigationService navigationService, string url)
    {
        var javaScriptService = new JavaScriptService();
        javaScriptService.Execute($"window.location.href = '{url}';");
    }
}

添加新的查找定位器

如果我们有办法添加新的自定义更高级的查找定位器,那就太棒了。

public class ByIdEndingWith : By
{
    public ByIdEndingWith(string value)
        : base(value)
    {
    }
    public override OpenQA.Selenium.By Convert() => OpenQA.Selenium.By.CssSelector($"[id^='{Value}']");
}

在Convert方法中,我们通过定位器使用一个标准的WebDriver,在这种情况下,我们通过一点CSS来实现我们的需求。

7.故障排除从容特性

随着测试数量和复杂性的增加,测试的可维护性将变得更加关键。这项工作的一个重要部分是简化故障诊断和更好地支持定位错误。

测试失败的整页截图

检测测试失败原因的最佳方法之一是查看web页面当时的屏幕截图。至少50%的时间,动作发生在屏幕不可见的部分,因为web页面超过一个屏幕。我们可以重用我已经提出的逻辑——使用WebDriver和HTML2Canvas.js捕获整个页面的屏幕截图

我们可以创建一个类似于重用浏览器的插件,而不是提及我们是否想要屏幕截图。


[TestClass]
[ScreenshotOnFail(true)]
[Browser(BrowserType.Chrome, BrowserBehavior.ReuseIfStarted)]
public class FullPageScreenshotsOnFailTests : WebTest
{
    [TestMethod]
    public void PromotionsPageOpened_When_PromotionsButtonClicked()
    {
        App.NavigationService.Navigate("http://demos.bellatrix.solutions/");
        var promotionsLink = App.ElementCreateService.CreateByLinkText<Anchor>("Promotions");
        promotionsLink.Click();
    }
}

测试失败视频

另一种查看测试失败原因的好方法是观看整个测试执行的视频。我们可以创建一个类似于失败时屏幕截图的插件。我们可以重用我已经与您分享的另一个解决方案——全栈测试自动化框架——测试失败时的视频录制

另外,如果我们能突出显示当前使用的元素,那就太棒了。为此,我们可以使用本文中的JavaScript解决方案——突出动作元素——通过观察者设计模式测试自动化框架的可扩展性。

[TestClass]
[VideoRecording(VideoRecordingMode.OnlyFail)]
[Browser(BrowserType.Chrome, BrowserBehavior.ReuseIfStarted)]
public class VideoRecordingTests : WebTest
{
    [TestMethod]
    public void PromotionsPageOpened_When_PromotionsButtonClicked()
    {
        App.NavigationService.Navigate("http://demos.bellatrix.solutions/");
        var promotionsLink = App.ElementCreateService.CreateByLinkText<Anchor>("Promotions");
        promotionsLink.Click();
    }
}

测量测试执行时间

有时,使用功能测试来衡量性能或确保它不慢是很有用的。 我们的框架可以提供一个称为ExecutionTimeUnder属性的新属性,您可以在其中指定超时。 如果对其执行测试,则测试失败。 public class MeasuredResponseTimesTests : WebTest 内置测试失效分析

无需检查代码或调试即可检测测试中是否存在问题或系统中是否存在错误。

我们可以重用以前提出另一个工具使用的责任链设计模式——失败的测试А分析——责任链设计模式。

在下一篇文章中,我们将继续描述“统一团队惯例功能”,“与现有工具和流程功能无缝集成”,“高级方案支持功能”特征的功能部分。 此外,您可以从下面的按钮下载开源测试自动化BELLATRIX的完整源代码。 它是功能最丰富的免费框架之一。 它支持Web,移动,API,桌面和负载测试。 我们将在接下来的所有文章中使用它作为展示。 因此,我建议您下载它,开始使用它,调试并查看代码。

author

石头 磊哥 seven 随便叫

company

thoughtworks

大家好,本人不才,目前依旧混迹于thoughtworks,做着一名看起来像全栈的QA,兴趣爱好前端,目前是thoughtworks 西安QA社区的leader,如果有兴趣分享话题,或者想加入tw,可以找我

roles

QA(营生) dev(front-end dev 兴趣爱好)

联系方式

如果想转载或者高薪挖我 请直接联系我 哈哈

wechat:

qileiwangnan

email:

qileilove@gmail.com