集成信息系统的End-2-End测试自动化。 第2部分。技术

在本文中,我们继续发表有关如何在一个主要的LANIT中进行自动化的项目的系列出版物,该项目是大型信息系统(以下称为“系统”)的手动测试(以下称为“自动测试”)的自动过程以及它的结果。

该出版物的第二部分主要集中在自动化小组UI端到端测试和领先的测试自动化的领导者。 在这里,他们将找到用于代码和部署的体系结构组织的特定方法,从而在面对测试规范不断变化的情况下,支持大规模并行测试的大规模开发。 这部分包含UI测试所需的完整功能列表以及一些实现细节,以及可能会遇到的意外情况。

在这里您将找到第1部分。(为什么需要自动化。开发和管理过程的组织。使用的组织)

来源

建筑与技术栈


系统的总体结构及其环境-高级设计


该项目中使用的主要技术和库:

  • JavaSE8&Maven&JUnit-开发堆栈;
  • Selenium-用于自动执行Web浏览器操作的库;
  • Selenide -Selenium的附加组件,它具有优雅的API,可大大简化与浏览器和页面元素的交互;
  • Selenoid&GGR -Selenium Grid和负载平衡器的实现,用于在CI服务器+通过浏览器预配置的容器上运行测试;
  • Yandex Allure-用于CI服务器上的报告。

下图显示了自动测试和Selenoid基础结构组件的一般图,其中包括解释性注释:

自动测试框架
用于用户界面回归自动化的应用程序。
提供源代码。 使用JUnit4

run.properties
配置文件以运行自动测试。 定义所用支架的条件名称和执行类型-本地或通过外部容器以及其他变量。

魅力插件
安装在Bamboo服务器上的特殊可执行文件。
创建可通过Bamboo服务器访问的测试HTML报告。

测试报告
可通过Bamboo服务器获得测试HTML报告。
它存储在计划结果中的Bamboo服务器上的单独选项卡中。

竹子
在自动和手动模式下提供集成测试的启动。
以Allure格式存储测试报告。

ggr服务器
Selenoid服务器的服务器平衡器。
提供从自动测试(RemoteWebDriver)到多个硒服务器实例的请求的平衡。

码头工人
Docker服务器运行Selenoid服务器容器和浏览器。

硒服务器
远程测试服务器
使用“无头”浏览器在专用Docker容器中启动测试。
根据指定的并发线程数以并行模式执行测试。

硒类
Selenoid服务器的服务器用户界面。
允许通过VNC动态监控测试进度。

硒网路驱动器
具有无头浏览器的专用容器,用于执行远程测试。
从Selenoid存储库提供。

Gitlab
存储自动测试应用程序的源代码。


工作计划


下图显示了“高级设计”级别上“自动测试”服务的一般方案。


安装与部署


自动测试基于四台服务器,其中一台是执行服务器,另外三台在容器中启动无头浏览器。 当前的自动测试功能可同时提供60个数据流,并在必要时可以扩展。

下图显示了当前的部署图。 通常,如果您不需要同时使用多个浏览器(测试线程)超过20个,则很有可能将所有内容都放在一台服务器上12个内核+ 24个RAM。 我们从这种配置开始,但是随着对自动测试功能的需求的增长,我们从经验中发现,最稳定且最具成本效益的配置是“典型”的12内核+ 24 RAM服务器。

根据我们的经验,对于在Angular上具有Web界面的系统进行测试,容器与浏览器的可接受配置应为内核层+ GB内存。 较小的配置会降低浏览器的速度,甚至可能导致无法识别的崩溃。


代码结构和组织


在继续进行代码的结构和组织之前,我将再次列出最终确定体系结构方向的政策和限制:

  • 大量复杂的端到端测试脚本。 高发展强度;
  • 测试场景的高度波动性(可变性);
  • 场景交付(开发和修订)的连续速度很高;
  • 自动测试开发人员的初始资格;
  • 开发人员的高计划开发。

基于上述内容,主要的体系结构驱动因素如下:

  • 确保高度结构化的代码,以易于阅读和管理;
  • 在特定测试的应用程序实现和通用功能的跨类之间实现最大程度的隔离和隔离;
  • 最大程度地减少所需依赖关系,以便于更改;
  • 在交叉类级别合理地重用代码,并在独立测试组(功能子系统)级别上进行可接受的可能的代码重复,以减少依赖关系并在开发级别上合并冲突;
  • 拒绝诸如spring,aspectJ之类的复杂框架,以减少新手开发人员“进入”项目的时间。

通常,这种架构方法使得在场景多变性的情况下,通过将新测试交付给生产人员的过程几乎是连续的,可以实现独立的快速开发。 尽管该系统已经实现了1,500多个业务场景,但该体系结构现在可以成功承受“负载和细化”。

下面给出了通用代码结构和关键特定解决方案的说明。

通用代码结构和开发模式


代码组织的一般结构基于“分层”体系结构(请参见图),该体系结构通常继承了Selenium开发人员推荐的页面模式。 我们通过向基础添加一个Web元素级别并突出显示测试场景的级别来扩展此模式:

  • 测试等级
  • 测试场景级别
  • 网页级别
  • 网络元素级别
  • 测试框架(在图中通过变暗显示)。

此方案中的每个级别都有一组特定的职责和功能。 不允许层之间的功能相交或层之间的非法依存关系,并且这是合并请求之前进行代码审查的一部分的返回修订版本的主要原因。

此外,在将代码划分为包的过程中,固定了“分层”结构(请参见下图)。

这种方案使得可以在开发人员之间划分所有子系统(其中子系统的数量远远超过该方案),结果,可以独立开发,而合并冲突却几乎消失了。

下图显示了测试类的实现的一般结构以及项目包的实现的分发方案。



测试等级


测试类别级别包括用于特定单个测试的单个类别(该测试在测试管理系统中被描述为线性的测试脚本序列)。 测试类是具有相应方法@Test注释的Junit类。 通常,测试类仅实现一种测试方法。

每个测试类都继承自一个基类,该基类的任务是初始化RuleChain中的所有TestRules,即初始化一个测试基础结构,例如初始化Web驱动程序,设置临时目录和其他通用util处理程序。

测试类负责通过以下方式组织测试方案的执行:

  1. 初始化测试业务数据(测试场景),
  2. 根据所需方案,依次调用各个测试脚本(动作),并从步骤2中将初始化的测试数据传输到这些脚本。

此外,在步骤2中,应该有一个线性序列,没有任何分支或决策点。 类实现模板如下所示。

测试用例级别


测试用例级别负责描述的特定测试用例的实现。 在这种情况下,测试场景是系统上用户通过与应用程序网页上的元素进行交互而执行的一系列操作。

测试用例类的主要目标是:

  • 通过使用Page的下层类的方法来执行测试脚本的给定序列

    o传输测试场景数据,
    o从网页(从Page类)接收的数据;
  • 在业务模型和测试场景的环境中执行所需的业务测试,以确保测试成功。 换句话说,测试用例类不检查元素的标记,可用性和可访问性,而是在测试场景的业务模型上运行,实际上是在进行业务测试。

测试用例类被组织为“功能接口”:

  • 仅包含一个公共方法“ apply”(@ Step),其中:

    o提供脚本的实现,作为对一系列“动作”(Page类提供的方法)的调用,
    o接受所有必要的业务对象作为输入,同时不创建任何业务对象本身,并且不与Page类以外的任何对象直接交互;
  • 包含X个私有方法(@ Step),每个方法都执行测试脚本的特定单独步骤(如TMS-测试管理系统中所述);
  • 不与其他活动,甚至是类似子系统的活动进行交互(不调用方法);
  • 不接受输入,也不对登录数据进行操作。 换句话说,对于启动它的角色一无所知。

这个班级组织可以使您:

  • 提供自我记录报告。 每种方法都对应于测试规范中的特定点,并由@Step的诱惑注释进行注释;
  • 在不同的测试中重用测试脚本类,因为测试脚本1)不创建测试场景,并且2)不依赖于用户的登录名(login-relogin操作在测试类级别执行)3),所以测试不依赖于其他类脚本。

网页级别


网页级别是在Selenium中进行测试的经典页面模式。 页面类包含特定Web元素的定义和一组公共方法,这些公共方法用于在测试用例步骤的上下文中执行某些组操作。

页面类直接负责将业务数据输入到特定的界面元素中,与Web驱动程序一起工作(例如,启动JS),并相应地测试格式,检查网页的布局和结构以进行以下基本检查:元素不是找到/不可用,并且该项目不包含必需的值。

页面类也不包含并且不能访问其他页面及其方法。 同样,页面类不执行业务检查,在一般情况下,它们仅将其限制为Web元素级别的结构检查,提供从页面接收的“测试脚本”级别的数据“最多”。

Web元素级别


Web元素层包括可能在网页上的有限元素库。 它既包含特定的原始元素,也包含更复杂的集团,由我们称为小部件的几个元素组成。 窗口小部件的示例可以是“构造器”,全局菜单,各种框架和模式窗口,复杂元素(例如YandexMap或Youtube播放器)等构造。 Web元素使用特定的页面类来组织组成,并且对其他元素一无所知。

通常,如果项目对所有具有其ID的接口元素进行某种全局唯一标识,则可以通过spring库中的factory或\ xml配置类将Web元素的级别组织为全局库,并通过其ID对特定元素的请求进行组织。 但是并非在每个项目中都有可能。

测试框架


如上图所示,开发自动测试的概念是基于一个框架的思想,在该框架中为所有自动测试提供了一组系统功能-它们被无缝集成,并允许自动测试开发人员专注于测试类业务实现的特定问题。

该框架包括以下功能块:

  • 规则-测试基础架构组件的初始化和完成,如WebDriver的初始化和接收视频测试(下面将详细介绍);
  • WebDriverHandlers-用于与Web驱动程序一起工作的辅助函数,例如执行Java脚本或访问浏览器日志。 实现为一组无静态方法;
  • WebElements-典型Web元素或其组的库,包含所需的跨功能功能和典型行为。 在我们的案例中,此功能包括可能在Web浏览器侧检查异步操作是否完成。 实现为Selenium和Selenide库中Web元素的扩展。

初始化测试环境。 规则


所有测试类的关键类是BaseTest,所有测试类均从该类继承。 BaseTest类定义了测试的Junit“运行器”以及所使用的RuleChain,如下所示。 通过使用线程标识符“ thread”作为键的规则类的静态方法,可以从应用程序测试类访问规则类提供的功能。

下一部分将显示自动测试框架的基类实现的详细信息:请参阅第2-1部分。 所有测试和JUnit ChainRule的基类实现。

通过魅力报告记录结果。


有关执行的测试的详细报告,请使用Allure框架,该框架通过Allure插件与Bamboo集成。 这为特定的测试使用者(功能测试团队)提供了机会,不仅可以接收有关特定测试崩溃的事实的数据,还可以轻松地还原数据,并在必要时以手动模式重复删除的测试。

要记录测试报告,请使用以下功能:

  • 用于根据测试脚本的步骤标记报告的Allure和Junit批注以及对测试元数据的静态描述;
  • 附有报告的诱人附件,例如视频测试,屏幕截图,崩溃原因的其他诊断结果,从文件浏览器下载到/从文件浏览器下载的Web浏览器日志。

以下Allure和Junit批注用于标记报告。

  • 在测试课程级别:

    o @ Feature-测试所属的功能子系统的名称;
    o @ Story-特定测试用例的名称;
    o @所有者-上次更改测试的开发人员的名称;
    o @ TmsLink-链接到使用的“测试管理系统”中的测试说明。
  • 在测试类的测试方法级别(@ Test)上:

    o @ DisplayName-测试脚本的全名。 它与@Story的不同之处在于,它允许您共享相同的脚本,只是在测试场景的组成方面有所不同。
  • 在与测试方案的特定步骤相对应的方法级别:

    o @步骤-测试步骤的有意义的名称,反映了所发生事情的业务本质。

通过@步骤来命名测试步骤,您可以创建详细的报告,该报告完全重复测试方案中描述的所有步骤和项目。 这使自动测试的用户可以轻松跟踪测试场景的过程,并有助于确定发生点。

通常,事实证明,使用Allure框架非常有用且容易,但有些功能与我们为大量长而复杂的测试脚本生成的大量数据有关(稍后将在“回顾”部分进行介绍)。

立即可以做些什么不同的事情? 使用Spring框架


尽管事实上在实现自动测试时,我们还是故意拒绝使用Spring Core,但总体而言,我认为使用它是合理且可行的。 所实现的原型表明,使用Spring Core可以完成以下任务(尽管我们当然没有对其进行全面测试):

  • 测试场景的初始化;
  • 网页和元素的初始化。

唯一的特点是需要使用原型级别的“默认”作用域上下文。

初始化测试场景。 在自动测试中,测试场景通过经典方法初始化,即通过简单的new或object工厂直接在测试类中创建类实例。 在这里,通过配置类或通过外部xml或文件文件使用初始化是非常合理的。 优点如下:1)简化了检查代码,因为对测试场景的更改不再适用于关键类别; 2)允许您针对不同的机架或其他条件连接不同的测试场景。 现在,第2点不与我们一起使用。

网页和元素的初始化。 网页类和Web元素的注入借助于硒化Web元素的延迟懒惰初始化而起作用。

因此,有可能根据用户界面的某个全局规范来创建Web元素和页面的库,并在代码中接收与这些元素的链接,而不是通过绝对路径和ID,而是通过根据规范的项目ID。

我必须立即说,我并没有非常仔细地测试它,实际上,我将自己局限于此原则上的登录“页面”和用户“信息”页面的测试实现。

回顾性的。 惊喜


在这里,我描述了在项目开发过程中出现的意想不到的惊喜,以及一些有关“如果不做的话”可以做得更好的考虑。

硒友好的前端标记(角度)


我们遇到的最严重的惊喜之一是“浮动”页面布局,该页面布局导致以下事实:更新Angular应用程序后,测试失败了,因为Selenium找不到元素,因为它们的ID(id,class或ng-model)或路径(对于XPath)。 这导致测试的不稳定以及跌倒原因的含糊不清。

不幸的是,这个问题通常是无法解决的。 我们通过组织措施规避了这一问题:1)在开始测试新的候选发布版本时,所有自动测试的开发人员都致力于在编辑Web元素定位器的值方面快速消除和完善功能; 2)最后,我们开始使用相对的XPath,可惜它根本无法提高性能。

理想情况下,与此类惊喜的斗争是在最初内置的实践中,即根据可在整个项目级别与业务数据和用户界面设计的全局域结构相关联的字典对所有界面元素进行唯一命名。

“下载”文件的文件名丢失


要从受测系统“上传”文件,我们使用以下解决方案:

  • 对于“本地”启动模式(直接在工作PC上启动)-初始化“本地”浏览器时,会将临时本地文件夹的名称作为参数传递给它。接下来,直接从本地文件夹读取文件以进行后续分析;
  • 对于“远程”模式(通过Bamboo),该文件是通过螺线管服务器的功能通过浏览器从容器中“获取”的:selenoid-host.example.com : 4444/download/{SESSION_ID►/{FILE_NAME}

详细信息在文档中进行了描述

对于这两种模式,要访问文件,都必须知道文件名。令人惊讶的是,因为我们不知道文件将以什么名称下载到容器中的磁盘上。本文的下一部分将介绍如何组织使用浏览器将文件从容器下载到自动测试的方式。

测试数据库阻塞


我们很快遇到了阻塞测试数据库的情况。首先,这是由于以下事实:为了通过测试场景的“整洁”,测试环境是在展位本身上动态生成的。例如,要检查将用户对象A添加到他的个人帐户中的功能,我们依次需要创建一个新用户,一个虚假合同对象A,并将其放置在特定地址,并且仅在所有初步测试脚本(在其中创建了测试场景)完成之后用于将对象A与用户链接的测试脚本。

很容易理解,过了一会儿,在用于放置对象的特定地址上,出现了成千上万个这样的对象。当对地址处的对象执行搜索操作时,这开始导致性能问题。

这是我们遇到的最惊人的例子。在这种情况下,我们只需定期移动到“新”地址,并且通常应定期执行旋转默认场景的过程,否则可能会出现令人不快的意外,这表现为通过测试的超时时间以及因超时而下降的测试时间。

高测试持续时间


在同时执行的测试数量增加的过程中,我们非常意外地遇到了此问题。我认为我们只是没有考虑过。完成全套测试(〜1000次完整测试)所花费的时间开始接近6小时的临界点。

为了增加同时运行的测试的数量,我们切换到Selenoid-ggr。这使我们可以将同时进行的junit线程数从20个(一台Selenoid服务器)增加到60个(三台服务器),然后我们便可以使用测试台的性能。 “突然”事实证明,测试台稳定地工作,同时进行的会话不超过60个。

当然,可以通过资源来提高生产率,但是问题是,当进行整夜测试或定期的preQA测试时,所有这些资源仅需要3-4个小时。其余时间资源处于空闲状态。当然,在这里,AWS立即提供每小时的服务器租金,特别是因为Selenoid解决方案非常适合这种方法,但是如果您的展位与Selenoid不在同一个AWS区域中,则可以闯入/闯入流量。
无论如何,在从项目开始就应该考虑在构建具有大量E2E测试的自测试系统时测试服务器和测试台本身的扩展性和性能问题。为此,值得依赖完全回归和preQA的最大运行时间的要求。

同时执行大量测试开始“风暴”


工作测试莫名其妙的崩溃是我们在60个浏览器中同时扩展60个测试流之后遇到的下一个惊喜。

在“时间轴”报告上,它看起来像“红色条”(如下图所示)。事实证明,这是由于测试台中单个服务的性能受到限制所致。


有两个原因。最初的“插入”是由于对授权服务和个人帐户的大规模呼吁而引起的。所有浏览器同时开始登录并在测试平台端使服务超载。

后来出现的“列”与以下事实有关:测试类按子系统位于文件夹中,而junit几乎同时运行它们,从而加载了机架的特定功能子系统,并超出了机架配置的性能极限。

我们通过将登录脚本方法包装在平衡器中解决了第一个问题,该方法将登录操作的最大数量限制为给定常数。

@Step(":    ")     public void apply(User user) {     try {         LoadCounter.get(); //   .              try {                 applyLogin(user); //          } catch (Throwable t) {             throw t; //                   } finally {             LoadCounter.release(); //            }         } catch (LoadCounterException e) { //                  throw new StandRuntimeException("Can not get loadcounter for Login action.", e);     }     } 

第二个问题是通过打开junit maven插件具有的random test run选项解决的。

    <plugin>               <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-surefire-plugin</artifactId>         <version>….</version>            <configuration>                <!-- Defines the order the tests will be run in. Supported values are "alphabetical",                     "reversealphabetical", "random","hourly", "failedfirst", "balanced" and "filesystem". -->                <runOrder>random</runOrder>                … 

必须指出的是,这些问题与以下事实有关:由于资源有限,我们没有机会提高测试台的性能,也因为这些资源大部分时间都是闲置的。

总的来说,事实证明,内置的E2E Web-UI自测系统很适合用于替代负载测试,并从整体上筛选测试系统的性能和稳定性。

Bamboo服务器及其存储上的高负载


如果您有许多涉及大量操作的测试(例如,通过Step记录的操作数量为200至2000,其中测试数量约为1300),则“魅力”报告的数量将变得不那么重要。 如果您还在此处添加各种附件(例如屏幕截图和上载/上载的文件),则该卷已经达到数百兆字节。 例如,现在对于900个测试的每晚回归,仅上传到Bamboo Allure的数据量约为600 MB。

显然,DevOps工程师对如此大的磁盘空间消耗并不热心,并积极表示不满意,尤其是在存储至少一年的数据方面。

通过使用用于存储和处理报告的外部服务器(例如Allure Enterprise),我们看到了解决这种情况的方法。 该服务器已经付款,但是可以解决此问题。 我们目前正在测试并将Allure Enterprise集成到我们的项目中。

待续


在下一篇文章中,我的同事将继续讲故事,并描述使用Smartbear SoapUI Pro测试Web服务的迷人历史。 两位自动化工程师的力量设法使大约500个测试脚本自动化;为此,我必须实现一个额外的框架,该框架显着扩展了标准SOAP UI函数的功能,但稍后会进行更多扩展。

本文是与项目经理和kotalesssk产品的所有者合作编写的。

第1部分。组织和管理。 为什么我们需要自动化。 组织开发和管理过程。 使用组织
第2部分。技术。 体系结构和技术堆栈。 实施细节和技术惊喜
第2-1部分。 所有测试和JUnit ChainRule的基类实现
第2-2部分。 使用浏览器将文件从容器上传到测试框架的过程的实现。 搜索浏览器下载的文件的名称

Source: https://habr.com/ru/post/zh-CN477044/


All Articles