风机知识

设备自动化测试

时间: 2025-01-09 13:04:34 作者: ng体育app官网入口

  作为 Netflix SDK 团队的一份子,我们应该负责确保新版 Netflix 应用程序经历彻底的测试,以最高运维质量部署到游戏主机平台,并以 SDK(以及参考应用程序)的方式交付给 Netflix 设备合作伙伴,最终发布到数百万智能电视和机顶盒中。总的来说,我们的测试需要确保 Netflix 能够在数百万游戏主机和网络电视 / 机顶盒中流畅运行。

  与服务器端的软件发布不同,针对这类设备发布会面临一些独特挑战,因为没有办法进行Red/black 推送,发生故障也无法立刻回滚。在将代码发布到客户端之后,如果客户端存在 Bug,修复成本将非常高。Netflix 必须重新召集已获得 Netflix 认证的设备合作伙伴,并在 Bug 修复后重新进行整个认证过程以进行确认,这要求我们与合作伙伴公司重新投入大量工程时间。而在这样的一个过程中,客户可能没办法解决自己所遇到的问题,只能暂时忍受不甚理想的 Netflix 使用体验。为了尽最大可能避免出现这种问题,最适合的做法是确保对设备做全面测试,在最终发布前找出应用程序中有几率存在的问题。

  本文是系列文章中的第 1 篇,主要介绍了我们在不同设备上针对 Netflix SDK 进行自动化的功能、性能,以及压力测试过程中所涉及的重要概念和所使用的基础架构。

  过去多年来,我们在 Netflix 应用程序的测试过程中同时使用了手工和自动化的方式,并获得了不少经验教训。因此在重新设计自动化系统,以便迈上一个新台阶并实现更大规模时,我们也将这些经验教训视作自己的核心目标。

  使用自动化方法时,测试的创建和 / 或使用的过程应该更简单。尤其是原本就很简单的手工测试,使用自动化方式后也一定要保持简单。这在某种程度上预示着自动化技术的运用,就算无法完全省略配置成本,也应让成本接近于零。因此我们一定要确保新测试的创建和现有测试的调试过程足够快速便捷,同时这也确保了能尽量只关注于测试和功能本身。

  使用自动化的系统不应对测试的具体形式产生限制,为了能在未来应用更为创新的测试,这一点至关重要。此外为了更好地满足多种团队(我们主要与负责平台、安全、播放 / 媒体 /UI 等的团队打交道)的需求,可能会通过不同方式设计自己的测试。将自动化系统与测试结构解耦有助于提高整个测试的可重用性。

  在构建大规模系统时,很容易最终创建出大量抽象层。虽然从根本上来看,大部分情况下这样的结果并没什么不好,但为了将这些层面与自动化系统集成在一起,还需要对这些层面本身来测试,这并不是我们大家都希望的。实际上除了真正要测试的功能外,需要测试的其他内容越多,遇上问题后的调试就越困难:应用程序之外有那么多东西需要测试,很容易在测试中造成错误。

  在我们的例子中,需要测试设备上运行的 Netflix,因此要确保设备上所进行的测试对不同功能的调用能够与被测试的 SDK 功能尽可能保持接近。

  手工方法的测试中,设备管理工作花掉了大量时间,因此这一领域很适合使用自动化系统。由于我们测试的都是正在开发中的产品,需要能随时更改构建版本并将其部署到设备上。为了尽量简化测试过程中所遇到错误后的调试过程,还需要自动实现日志文件和崩溃转储文件的自动化提取。

  确立了这些目标后,毫无疑问我们的团队需要一种能提供必要自动化机制与设备服务,同时尽量不对测试过程产生干扰的系统。

  这就要重新思考现有的框架并创建出一个全新的自动化ECO。为了通过自动化获得所需灵活性,需要让这个自动化系统足够精益,采用模块化设计,并且仅在功能测试非常必要的时候才使用外部服务,也就是说只有在功能无法直接通过设备上的应用程序实现(例如暂挂应用程序或操作网络)时才使用外部服务。

  测试框架意在帮助编写测试,为减少对测试故障进行调试时需要检查的活动部件数量,应尽可能与要测试的设备 / 应用程序保持密切相关。

  一套外部的后端服务,能够在一定程度上帮助管理设备,自动执行测试,并在必要时提供测试所需的外部功能。自动化服务应该尽可能以自成体系的独立方式构建。减少不同服务之间技术层的数量有助于实现更好的可重用性、可维护性,以及更简单的调试和后续完善。例如对测试的启动过程提供帮助的服务,收集测试运行过程中信息的服务,验证测试结果的服务,都可以委派给不同的微服务实现。这些微服务可以对测试的独立进行提供帮助,但不是运行测试所必须的。自动化服务只应该用于提供服务,不能用于控制测试流。

  虽然测试本身是自动实现的,但针对不一样类型的设备构建测试有必要进行大量自定义操作,例如刷机、升级,然后启动应用程序开始做测试,并在测试结束后收集日志和崩溃转储数据。不同设备上每个此类操作可能都各不相同。我们需要通过服务将不同设备的具体信息抽象出来,并为不同设备提供一个通用接口。

  为确保不间断提供高质量的播放体验,在带宽状况波动的设备上对 Netflix 应用程序来测试成了我们的一个核心要求。我们应该通过一种服务更改网络环境,包括流量塑形以及 DNS 控制。

  在出于归档目的收集不同构建版本,或需要存储海量日志文件时,我们需要能通过某种方式存储并获取这些文件,为此实施了一套文件服务。

  由于每个服务是相对独立的,因此我们需要通过某种调度编排程序与不同服务进行通信,以便在测试开始前让设备做好准备,并在测试结束后收集结果。

  上述服务通过进一步完善即可满足我们的需求,并且各种服务尽可能保持独立,并为与测试框架进行捆绑。这些概念是按照下列方式执行的。

  设备服务可对测试自始至终全程管理设备所需的技术细节进行抽象。通过对所有类型的设备提供一个简单、统一的 RESTful 接口,无须对特定设备有具体了解即可直接通过该服务使用不同的设备:可以像对待完全相同的设备那样直接使用全部或任何一种设备。

  管理每类设备所需的逻辑并非直接在设备服务自身中直接实现的,而是会委派给名为Device handler的独立微服务。

  这样既可灵活增添对新类型设备的支持,因为 Device handler 可以通过任何编程语言用相应的 REST API 编写,现有 Handler 也可以轻松集成到设备服务中。一些 Handler 有时候可能需要与设备建立物理连接,因此将设备服务与 Device handler 解耦即可忽略设备位置获得更大灵活性。

  对于收到的每个请求,设备服务将负责确定要联系的 Device handler,并在针对所使用的 Device handler 接口进行适配后,以代理的方式将请求发送给不同 Handler。

  一起用一个具体的例子看看… 举例来说,为 PS4 安装某一构建版本的操作与为 Roku 安装的过程就有很大不同。前者(PlayStation)需要使用 C#编写的代码与 Windows 平台上的 ProDG Target Manager 进行交互,后者则需要在 Linux 上运行使用 Node.js 编写的代码。PS4 和 Roku 的 Device handler 分别实施了特定于具体设备的安装程序。

  如果设备服务需要与某个设备通信,必须首先知道该设备的具体信息。每个设备都有自己的唯一标识符,设备服务将其以设备映射对象(Map object)的形式存储和访问,其中包含了 Handler 所需的设备信息,例如:

  当需要对某个新类型设备来测试时,要针对该设备实现一个专门的 Handler,并通过设备服务暴露。设备服务支持下列常用的设备方法:

  请注意,针对上述每个端点发送请求时都需要提供一个唯一标识符。这个标识符(类似于序列号)会和要操作的设备绑定。

  保持这套服务尽量简单,也能尽量提高其扩展性。我们可以轻松地为不同设备增加其他能力,如果某个设备不能支持这些能力,将其视作空指令(NOOP)即可。

  下图是我们在实验室中进行自动化测试时用到的部分设备。请留意 Xbox 360 电源按钮旁边添加的手动机械开关。这是我们为 Xbox 360 量身打造的自定义解决方案。该设备需要手工按下按钮才能重启动,我们决定设计一套通过树莓派(Raspberry Pi)连接的机械臂让这一过程实现自动化,通过发送信号即可让机械臂按下电源按钮。这一操作已添加至 Xbox 360 的 Device handler 中。设备服务的电源周期(Powercycle)端点可以调用 Xbox 360 的电源周期 Handler。PS3 和 PS4 无须这一操作,因此未将其实施到它们的 Handler 中。

  测试服务负责对测试案例的运行进行记录。其用途在于标记测试案例的开始,并在测试结束前持续记录状态的变化,用日志保存相关信息、元数据、文件链接(测试过程中收集的日志 / 小型崩溃转储文件),以及测试案例所生成的所有数据序列。该服务暴露的简单端点可被运行测试案例所需的测试框架所引用:

  为了与设备通信,以及进行流量塑形和 DNS 控制,我们开发了一个名为 Bifröst Bridge 的网络系统。我们并没有更改网络拓扑,而是直接将设备连接至主网络。Bifröst Bridge 并非运行测试所必须的,只有测试需要对网络进行操控,例如更改 DNS 记录时才会可选使用。

  运行测试的过程中,我们可以收集测试生成的文件并通过文件服务将其上传至存储仓库。收集的内容包括设备日志文件、崩溃报告、屏幕截图等。从面向消费者的客户端角度来看,这个服务的使用非常简单:

  文件服务基于云存储平台,为了快速检索,还通过Varnish Cache对资源创建了缓存。

  我们选择使用 MongoDB 作为测试服务所用的数据库,因为这种数据库可支持 JSON 格式和“无架构(Schema-less)特性。通过开放式 JSON 文档存储解决方案获得的灵活性是这套系统的关键需求,因为测试结果和元数据的存储会不断变化,不应受到结构的限制。虽然从数据库管理的角度来看,使用关系性数据库也很合理,但我们以“即插即用”为基本原则,因此无论测试需求如何,数据库的架构都必须用手工的方式保持最新。

  通过使用CI模式运行,每次测试可以记录一个唯一的运行 ID,并借此收集有关构建配置、设备配置、测试详情等信息。日志文件在文件服务中的下载链接也会存储在数据库的测试项中。

  为了减轻每个测试发起人分别使用不同服务运行不同测试所面临的负担,我们开发了一个名为 Maze Runner 的控制器,该控制器可以对测试的运行进行编排,并按需调用不同的服务。

  测试套件的所有者可以通过创建脚本指定用于运行测试的设备(或设备类型),并结合测试套件的名称和测试案例组成一个测试套件,随后由 Maze Runner(并行)执行该测试。

  如果测试未能启动或未能终止(超时),Maze Runner 会使用设备服务检查应用程序是否已经崩溃。

  如果检测到崩溃,则会收集核心转储(Coredump),生成调用栈(Call stack),通过一个专有的调用栈分类器进行检查,找出崩溃的特征签名。

  在上述过程的任何一刻,如果 Maze Runner 检测到设备存在问题(例如因为丢失网络连接导致构建未能安装或设备未能启动),它将会释放该设备,让设备服务将其禁用一段时间,并通过另一个全新的设备开始运行测试。这样做是因为纯粹的设备故障不应对测试产生影响。

  测试框架完全独立于自动化服务,因为测试框架只是用于在设备上运行测试所用。大部分测试可以无须自动化服务手工运行,而这也是设计这套系统时的一个核心原则。这种情况下可以手工启动测试,并在测试完成后的手工获得并查阅结果。

  然而测试框架也可以配合自动化服务使用(例如用测试服务存储测试进度和结果)。如果通过运行器在 CI 中运行测试,我们应该将其与自动化服务相集成。

  为了用灵活的方式实现这一目标,我们创建了一个在内部被称之为 TPL(Test Portability Layer)的抽象层。测试和测试框架通过调用这个抽象层可以为每个自动化服务定义一个简单的接口。每个自动化服务可提供这些接口所需的实现。

  针对该系统所实现的服务,这个抽象层可以让原本需要自动运行的测试可以通过 TPL 接口提供的截然不同的自动化系统来运行。这样就可以让其他团队(使用其他自动化系统)编写的测试案例不经改动直接运行。如果测试无须改动,设备上测试运行失败后就无须由测试的所有者进行排错,这正是我们大家都希望实现的。

  通过让测试框架与自动化服务保持独立,按需使用自动化服务并增添所需的设备功能,我们实现了:

  从最新的测试执行覆盖图中能够正常的看到,仅针对参考应用程序,每个构建版本已执行了大概 1500 次测试。从全局的角度来看,开发团队每天会为每个分支生成大约 10-15 个构建版本,每个版本包含 5 个不同用途(例如调试、发布、AddressSanitizer 等)的参考应用程序。对游戏主机,每天每个用途会生成大约 3-4 个构建版本。总的来说,针对单一用途的构建版本,我们的生态系统每天可以运行大约 1500*10 + 1500*3,即大约 2 万个测试案例。

  在后续文章中,我们将深入介绍未解决上述两大挑战,目前我们所采取的一系列创新措施。

  给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至也欢迎各位通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

  随着规模的逐步扩大,Netflix面临身份验证难题,不仅有多种协议、多个令牌,而且面对2亿多用户和数千种设备类型。怎么样才能解决这种复杂性,Netflix提出了一种新方案。

  这种方法消除了不稳定测试对CI和SQ的所有影响,从而大幅度的提升了软件可靠性和研发人员生产力。

  在这一讲中,我会通过 GitLab 持续集成与金丝雀发布这两个具体的例子,来为你具体介绍一下怎么为这些过程建立可观测性。

  Netflix最近完成了为期一年的项目重构工作,将Android应用的API后端从单体切换到微服务。本文讨论了迁移方法、采用的策略。

  这篇文章介绍,怎么样去使用杂项设备框架编写一个简单的按键驱动,完成编写、编译、安装、测试等流程,了解一个杂项字符设备驱动的开发流程。

  当我们理解TDD之后我们至少会发现下面这三点: 1. TDD是一种更加自然的编程方式 2. 先写测试还要求我们站在使用者的角度来编写测试,这样做才能够自然的驱动出更好的设计 3. 由于TDD天然的特性,无需担心测试覆盖率不够

  移动端 app 自动化框架很多,但是有一些框架因为不支持混合应用测试,始终没完全流行。很典型的是经典的 Python 框架 uiautomator2, 这个框架简单好用,没有 appium 那样复杂的 api 调用,受到不少 python 自动化工程师的青睐。

  为了帮你检验自己的学习效果,我特意给你准备了一套结课测试题(可以重复体验)。一共 10 道选择题,3道单选题,7道多选题,都来自我们前面讲到的重要知识。点击下面按钮开始测试吧!

  在很多讲TDD测试的书或文章中,通常会偏概念化,希望能够通过今天的学习,你能对它有更具象的了解。

  移动端 app 自动化框架很多,但是有一些框架因为不支持混合应用测试,始终没完全流行。很典型的是经典的 Python 框架 uiautomator2, 这个框架简单好用,没有 appium 那样复杂的 api 调用,受到不少 python 自动化工程师的青睐。

  该自主测试扩展使用随机输入来发现 bug,并利用软件栈的同质性来提供无缝的开发体验,鼓励快速迭代。

  前面的两讲让我们有了理论基础和算法,现在终于能来说说测试用例如何被生成出来了。

  分析开发者的行为模式、工作价值、职业发展等内容,帮助整个行业生态更深入地理解开发者,为他们提供更精准...

首页
产品
新闻
联系