融云分析

融云分析

手机端看不到自己发的消息

IM即时通讯admin 回复了问题 • 1 人关注 • 1 个回复 • 208 次浏览 • 2020-11-05 14:24 • 来自相关话题

【融云分析】SDK 交付质量保障之自动化测试

IM即时通讯融云那些事 发表了文章 • 0 个评论 • 197 次浏览 • 2020-07-24 12:29 • 来自相关话题

² 自动化测试的意义很多测试人员说到自动化测试领域,反应就是的接口自动化、Web 自动化、APP 自动化、Selenium、Appium 等等。其实这些都是针对于测试工作,用来解决问题时已经比较成熟的工具或方案,相信随着自动化领域的发展,对应自动化测... ...查看全部

² 自动化测试的意义

很多测试人员说到自动化测试领域,反应就是接口自动化、Web 自动化、APP 自动化、Selenium、Appium 等等。其实这些都是针对于测试工作,用来解决问题时已经比较成熟的工具或方案,相信随着自动化领域的发展,对应自动化测试工具,方案也会越来越丰富。

相对于手工测试而言,自动化测试本质上是使用代码或者工具,把复杂的测试工作从手动转化成为机器自动执行。优秀的框架、工具可以借鉴使用,但不要过于局限于现有工具和框架,而应根据自身产品特性和架构特性,寻找适合当前产品的自动化测试解决方案才是合理的自动化测试。

² 融云自动化测试实践

以融云的业务为例,在融云实时音视频 SDK 的质量保证上,有大量的测试点需要关注,例如:噪声啸叫抑制、回声消除、清晰度、首帧速度、移动端性能、耗电量、流量控制、延时、丢包等。

除了上述音视频质量检测以外,对于一个 SDK 基础服务来说,还有些需要重点关注的指标就是连通率指标,连通速度指标。而且该指标想达到 99.9% 以上的标准,那么针对每个功能修改,版本发布,测试次数需要数千次数万次的成功连通测试才能验证。

一、保障实时音视频 SDK 质量应具备的条件

音视频 SDK 测试需要测试不同厂商的客户端设备,对 SDK 画面渲染、稳定性、视音频连通等各种表现情况。因此我们还需要在单元测试的基础上,引入移动端,web 端的自动化测试检查客户端的具体表现能力。

1. 测试框架及工具的整合,建立稳定的 UI 自动化测试脚本  

Appium & Selenium 作为测试框架,可以支持iOS,Android,Chrome,Firefox 等多种驱动。并且无需对测试应用做任何嵌入式的修改,开源社区也相对活跃,作为UI自动化测试是一个比较好的选择。Python + Pytest 作为快速开发的语言和单元测试框架,可以提升测试脚本整体开发效率。

下面是 Appium & Selenium 基本工作原理:

 自动化测试1_副本.png

 

接触过 UI 自动化的同学,很多都会觉得 UI 自动化测试相对于接口、单元测试来说并不稳,尤其是遇到长时间运行几十个小时、几千上万条用例时,稳定性阻碍使用的一大难题,我们针对一些经常出现的问题进行解决。

 

元素不定期出现变化

对于元素不定期变化的问题,与团队进行沟通协调当然必不可少,也是最容易解决问题的方法,当然还有很多其他方式。

 

Page Object 设计模式对于 UI 测试来说就是一个不错的选择,Python3 有个升级就是全面 Unicode化,就是可以使用用中文命名变量,对于页面静态变量这种元素修改、查错来说效率还是可以提高不少。例如:

自动化测试2_副本.png


设备断开 & 网络异常

设备断开这个应该是阻断 UI 自动化常出现的问题了,数据线闪断、客户端服务 Crash、远程连接网络异常等,这时候重连机制就尤为重要了。针对这个问题我们可以给每个用例加增加装饰器函数如果用例失败并且检测到断开则立即重连;也可以用 Pytest 内置钩子函数使用方法检测断开重连,示例:

 自动化测试3_副本.png 

 

意外弹窗问题

很多厂商设备在你运行用例的时候,经常会弹出个窗口,这是非常头痛的,但是基本上所有的弹出按钮都是 Android: //android.widget.Button,iOS: //XCUIElementTypeButton 两种类型的 xpath。因此我们只需要在报错时,获取页面上所有这两种类型的文本处理一下即可,尽量不堵塞后续用例的运行。简单示例:

 自动化测试4_副本.png

 

良好的测试用例设计

无论是从事何职的测试人员,测试用例设计都应该是关注的重点,一个好的自动化测试用例设计可以发现更多的问题,也可以让用例运行更加稳定。

 

2. 提供多样丰富的测试数据,不放过每一次问题

在我们运行自动化测试时,检测到崩溃、黑屏、绿屏、花屏等异常错误的时候,需要尽可能地提供详细测试报告数据才能更加准确地定位问题。

 

移动端关键错误截图和日志

自动化测试的报错截图,比较好获取,但是日志内容是客户端查询的关键。ADB 或者 idevicesyslog 等工具虽然可以获取到手机日志,但是在脚本运行过程中,不容易精确定位并截取到测试用例开始到结束这段时间日志内容。

 

实际上 Appium 会自带日志缓冲区,在脚本运行的时,Appium 工具将移动端日志写入日志缓冲区。但是Appium 并没有提供 API 修改缓冲区大小,也无法筛选关键日志,因此我们针对 appium-xcuitest-driver、appium-android-driver、appium-adb 等库进行了符合自己产品需求的修改,可以进行日志过滤筛选主动触发清理缓冲区,使定位问题更加精确,测试报告更加完善。

 

移动端关键错误网络抓包

遇到错误时,网络交互数据也是检查错误的重要数据,我们需要利用 Wireshark 工具进行抓包截取部分网络抓包数据,针对 iOS 设备可以用 rvictl 命令 生成虚拟网卡,Android 设备则需要使用共享 Wifi 模式。之后利用 Wireshark  dumpcap 指定网卡和筛选数据。同日志抓取一样,通过钩子函数我们在用例开始和结束时精确地定位到错误区间,并将抓包数据添加到测试报告中,提供给相关人员排查依据。

3. 测试任务调度平台

测试平台有主要分发测试任务和运行自动化测试任务两种。我们希望测试人员无需部署任何环境或者进行简单部署,就可以快速接入平台运行自动化测试,查看测试报告。不需要限定固定的移动设备来连接在固定机器上执行自动化测试。

 自动化测试5_副本.png


上图我们针对 Android 可以使用 ADB server 服务器。自动化测试测试脚本 Appium 服务器利用 ADB 传输协议,通过局域网链接子节点 Agent 服务进行测试,这样可以让设备不受限制,连接局域网任意本人或者空闲电脑,运行子节点 Agent 即可立即运行自动化测试,空闲设备利用起来,我们就有了庞大的测试机器群了,使设备即插即用使用率最大化。

 

但是 iOS 系统特性限制,虽然有 WiFi 共享模式,但使用起来稳定性并不友好。因此需要在 MAC Agent机器上环境部署本地的 Appium 等相关服务,设备直连该机器通过平台执行自动化测试

 

二、移动端 IM SDK,要做到接口全覆盖测试

客户端 SDK 是为第三方开发者提供的软件开发工具包,工具包的形式集成在 App 内,一个 App 内可能包含了多个 SDK 工具包。一个 SDK 对外发布后,我们可以建议开发者如何调用 SDK,但是无法预计开发者怎样调用 SDK 的接口。因此一个稳定的 SDK 工具包就显得尤为重要。

 

SDK 接口要做到全字段校验才能保证稳定性。

SDK 测试方法中,单元测试虽然可以更加的高效和稳定,但是单元测试无法轻松地在不同的设备范围运行,也无法针对打包集成后 SDK 包的功能进行检测,从而无法检测 SDK 在各大应用设备上的集成表现以及开发者在集成时候所遇到的问题。

 

 

IM SDK 自动化测试解决方案。

做自动化测试,主要解决的问题是:

1) 核心通信能力尽可能的脱离 UI 自动化测试,做到快速迭代的能力;

2) 可以任意对 SDK 接口字段进行自由组合校验;

3) 可以测试覆盖单设备多应用测试场景。

 自动化测试6_副本.png

 

由上图可看出基本结构并不复杂,主要是根据约定 JSON 格式和 Demo 层中的 Server 进行通信,Server Demo 通过反射或者自定义等方式调用 IM SDK 的接口,这样使我们可以对SDK 的接口参数进行自由的组合,从而验证 SDK 在复杂的测试用例中,是否能保证产品质量的稳定性和异常参数回调的友好提示等。

 

打包后的IM SDK 自动化测试,使移动端 IM SDK 基础服务不再只依赖于 UI 层的 Demo 测试,可测试范围和版本回归效率能提升数十倍。

² 自动化测试的测试成本&预期收益平衡

 

软硬件行业自动化趋势在近年来愈发明显,当然自动化测试也随之一步步更加成熟,但是要做自动化测试,肯定要考虑测试成本和预期的收益。

 

虽然自动化测试可以在任何时候都可以自动运行,看似节省了时间,但是需要考虑到自动化脚本前期开发的时间成本和后期脚本的维护成本,而且自动化效率较为依赖用例设计,自动化测试用例的开发工作量有时会比手工测试的工作量还要大。项目开发周期短、业务新、测试业务主观性很强等类型的产品要慎重考虑。

 

自动化测试能带来哪些收益也是大家最关心的,自动化测试一个重要的特性就是一致性,它不会随着时间增长出现由于人的疲劳所带来的漏测、漏记,可增加版本发布的信任。由于测试是自动执行的,所以执行过程中极少会出现疏忽错误,当然这也取决于自动化测试脚本的设计质量。

 

在立项初期如果考虑使用自动化测试,一定要考虑清楚自动化测试目标是什么,用自动化测试来解决什么问题,如果想用自动化测试来节省人力成本显然是不合适的,自动化测试的首要目标应当是如何提高产品的质量。

 

以上就是融云在自动化测试实践中的一些所感所得,我们将其记录和整理,并与大家分享,也欢迎更多的技术小伙伴与我们一起探讨。

 

点击查看原文


 最新活动推荐:

融云年中大促活动海报.png


【融云分析】苹果 iOS 通知推送机制全面解析

IM即时通讯融云那些事 发表了文章 • 0 个评论 • 245 次浏览 • 2020-07-17 15:50 • 来自相关话题

在当下的 App 开发中,通知功能已成为不可或缺的一部分,目前主要分为两种模式:本地通知和远程推送。本文将围绕这两种模式,为开发者们详细介绍下 iOS 通知推送机制。本地通知一、本地通知介绍指定推送时间,该时间在手机上弹出推送通知,不需要网络连接,例如日历、待... ...查看全部

在当下的 App 开发中,通知功能已成为不可或缺的一部分,目前主要分为两种模式:本地通知和远程推送。本文将围绕这两种模式,为开发者们详细介绍下 iOS 通知推送机制。

本地通知

一、本地通知介绍

指定推送时间,该时间在手机上弹出推送通知,不需要网络连接,例如日历、待办、闹钟等应用。

更多详情请点击 ☞ Scheduling and Handling Local Notifications 

二、本地通知使用

1. 在代码中注册本地通知

如果是 iOS 7 及之前的设备,不需要开发者添加代码即可使用(用户需要打开 App 通知)。 

如果是 iOS 8 – iOS 10 之间的设备,直接用下方代码(通过注册本地通知)注册即可。 

如果是 iOS 10 以上的设备,需要在 Appdelegate 中导入 #import <UserNotifications/UserNotifications.h>,并遵循 UNUserNotificationCenterDelegate(在 iOS 10 中,苹果针对远程推送和本地通知推出了全新的 UserNotifications 框架),如下:

2. 发送本地通知

3. 取消本地通知

4. 处理收到的本地通知

4.1 应用处于前台运行状态

4.2 应用处于后台活跃状态

4.3 应用处于后台暂停或者被杀死状态


远程推送

一、远程推送介绍

更多详情请点击 ☞ APNs Overview

Provider:App Server

APNs:Apple Push Notification Service

远程推送工作流程

二、远程推送类型

1. 普通推送

服务端通过 APNs 推送到手机的一种消息通知,包括:声音、横幅、角标和自定义字段。

通知内容格式如下:

2. VoIP 推送

更多详情请点击 ☞ Voice Over IP (VoIP) Best Practices 

iOS 8 之后推出,依赖 PushKit.framework,主要用于音视频通话时响铃,VoIP 推送可以在应用被杀死的情况下唤醒 App。

使用时需要在 Signing & Capabilities 的 Background Modes 中打开 VoIP、Background fetch 和 Remote notification,并添加 PushKit.framework。

从 iOS 13 开始苹果为防止 VoIP 推送被非来电功能滥用,禁止在非来电功能中使用 VoIP 推送,如果使用 VoIP 推送只能使用 iOS 系统的 CallKit.framework 库,如果不使用 iOS 系统的 CallKit.framework 库,App 在收到 VoIP 推送后会被杀掉,表现上就类似于没有收到 VoIP 推送;由于苹果限制中国区域使用 iOS 系统的 CallKit.framework 库,导致 VoIP 推送功能也无法在苹果商店审核通过,可以将 VoIP 推送转成 APNs 解决,融云 iOS 13 以上 VoIP 功能适配

3. 静默推送

iOS 7 版本之后推出的一种特殊远程推送,又称为后台远程推送。这一推送的特征是收到通知时没有弹窗、横幅和声音,这时不用点开通知,不用打开 App 就会执行下面的方法:

注:1. 需要开启 Remote notifications 和 开启远程推送功能 

2. 静默推送的字段中不允许携带 alert、badge 和 sound 等字段,必须包含 content-available。

三、iOS 远程推送配置

1. 申请证书及配置文件

1.1 创建 App ID

1.1.1 登录 Apple Developer,进入 Identifiers,点击“+”按钮。

1.1.2 创建 App ID(如果 App ID 已经存在可以直接跳过此步骤)

注: App 的 BundleID 不能使用通配符,否则将无法使用远程推送服务。

1.1.3 开启远程推送服务

1.2 创建推送证书

1.2.1 创建 Push 证书

1.2.2 选择新建的证书类型(开发或者生产)

注:从 iOS 9.2 开始,Apple Developer 上生成的生产环境推送证书,名称为 Apple Push Services: XXX, 之前生成的生产环境推送证书名称为 Apple Production IOS Push Services: XXX。

1.2.3 选择要开启远程推送的 App ID,点击 Continue 后会提示需要一个 CSR 文件,CSR 文件需要参考 1.2.4 生成

1.2.4 生成 CSR 文件,用于上传

•打开 Mac 系统自带的钥匙串访问;

•从证书颁发机构请求证书;

•将请求的 CSR 保存到磁盘。

1.2.5 上传 Certificate Signing Request(CSR) 文件

将 1.2.4 中生成的 .certSigningRequest 文件上传,点击 Continue 即可生成推送证书。

1.2.6 下载生成的推送证书,并导出 .p12 文件

双击下载的推送证书,系统会将其导入钥匙串中。打开钥匙串访问,选中对应的证书,右键选择导出。保存 .p12 文件时,可以为其设置密码,也可以不设置密码。

注意右键选择导出的时候不要打开证书,直接在证书上点击右键即可。

1.3 创建配置文件

1.3.1 创建 Profiles

1.3.2 选择对应环境

1.3.3 为配置文件关联 App ID

1.3.4 选择开发者证书

1.3.5 选择要安装的设备

1.3.5 填写 Profile Name

1.3.6 下载后双击,即添加到 Xcode 中

2. 代码处理

2.1 在代码中注册远程推送

如果是 iOS 10 以上的设备,需要在 Appdelegate 中导入 #import <UserNotifications/UserNotifications.h>,并遵循 UNUserNotificationCenterDelegate(在 iOS 10 中,苹果针对远程推送和本地通知推出了全新的 UserNotifications 框架),如下:

#if __IPHONE_10_0

#import <UserNotifications/UserNotifications.h>

#endif

注册远程推送相关代码:

2.2. 处理 deviceToken

如果处理 deviceToken 的方法是通过去掉 [deviceToken description] 的 “<“、”>” 和 “空格” 的话,iOS 13 之前的设备可以获取到正确的 deviceToken,但是在 iOS 13 之后就无法获取正确的 deviceToken;因为 iOS 13 之后通过 [deviceToken description] 获取到的字符串变成了下面这样的格式:

现在应该采用的获取 deviceToken 的方法:

3. 处理收到的远程推送

3.1 应用处于前台运行状态

App 前台可见时,处于前台状态。

3.1.1 收到远程推送会回调下面的方法

3.1.2 点击远程推送会回调下面的方法

3.2 应用处于后台活跃状态

当 App 进入后台未被系统回收时,处于后台活跃状态。

3.2.1 点击弹窗会启动应用并回调下面的方法

3.3 应用处于后台暂停或者被杀死状态

当 App 进入后台被系统回收或者被杀进程,处于后台暂停状态。

四、iOS 远程推送扩展

1. 修改通知内容

利用 iOS 10 新增的 Notification Service Extension 可以修改收到的远程推送内容。

注意:

1.1 只在 iOS 10 以上有效;

1.2 后台推送过来的数据要协商好格式;

1.3 Targets 中的 Service Extension 的系统版本需要修改为 10.0,如果版本高于测试设备的系统版本,则不会走对应的方法。

具体步骤如下:

•给工程添加一个 target :Notification Service Extension。

•主工程开启 Push Notifications 和 Background Modes 功能。

•Service Extension target 开启 Push Notifications 功能。

•NotificationService.m 中实现 – (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler :

【融云分析】关于测试驱动开发(TDD)的感悟

科技创新张雷 发表了文章 • 0 个评论 • 58 次浏览 • 2020-06-16 18:26 • 来自相关话题

提起测试驱动开发(以下简称“TDD”),圈内工程师对其都有一定程度的了解,TDD 的优点也得到了普遍的认可。有研究机构曾对微软和 IBM 的八个开发小组进行了对照测试,结果发现使用了 TDD 的小组比未使用的小组在问题发生比例上减少了四至九成。在结对编程的相关... ...查看全部

提起测试驱动开发(以下简称“TDD”),圈内工程师对其都有一定程度的了解,TDD 的优点也得到了普遍的认可。有研究机构曾对微软和 IBM 的八个开发小组进行了对照测试,结果发现使用了 TDD 的小组比未使用的小组在问题发生比例上减少了四至九成。在结对编程的相关实验中,使用 TDD 的小组比未使用的小组在黑箱测试通过率上平均高出 18%,效果相当明显。

但反观日常所接触的实际工作中,对于 TDD 的使用并不多见,码农们对其价值也褒贬不一,网上甚至有大咖写文章公开论述观点来反对它,这又是为什么呢?前不久我刚好在融云的一个项目里小范围实践了一把,我就试着结合各方观点,斗胆谈谈自己的体会。

首先介绍一下什么是 TDD,TDD 最早是由 Kent Beck 提出并在他的《Test-Driven Development By Example》一书中进行详细阐述的(Kent Beck也是极限编程 Extreme Programming 概念的提出者)。书中所述:TDD 就是以测试作为开发过程的中心,要求编写任何产品代码之前,首先编写用于定义产品代码行为的测试,而编写的产品代码又要以使测试通过为目标的软件工程方法,目的是构造简单、清晰、高质量的代码。

测试是保证软件质量的重要手段,一个公司的研发部门通常都会有很大比例的测试团队作为质量保证的坚实后盾。那么作为开发人员是不是就可以只关心写代码的进度,编译通过后再跑几遍没问题就提交代码呢?这样的程序在碰上初始条件稍有改变,或者压力、并发等外部因素略有变化下会不会出现崩溃等问题呢?有的团队会制定规章制度,要求给完成的代码编写测试用例,必须通过才可以提交。这或许能在一定程度上使情况得到改善,但实际效果真的有那么明显么?我就听过有人抱怨说,完成代码后再写测试用例是浪费时间,因为对逻辑走向已十分了解,测试自然不会有什么大的纰漏,有那个时间不如多写几行代码,反正有测试团队兜底。乍一听似有道理,但仔细一想实则是在逃避责任,也在浪费公司资源。

那保证软件质量,有何良策呢?让我们来看 TDD 是如何做的,前面说过 TDD 的精髓在于将测试前置,这看似微不足道的变化到底会带来怎样的化学反应呢?

第一,能够明确目的。在动手编写生产代码之前,就得先想好这一部分逻辑的输入输出是什么,编写满足需求的测试用例,同时增加对需求的强化理解。举个简单的例子,与合作开发的同事对好需求,划分好各自实现的逻辑块,结果后续联调时才发现一方理解错了意思,之前的工作量就白费了。有了这提前编写的测试代码,就能逻辑层面再次明确目标,避免语言文字上的误解。在编写代码过程中,更容易做到心无旁骛,思绪不会乱飘,因为你的目标就是编写能通过测试用例的代码。当然这一过程可能会需要持续对测试目标进行完善,即所谓的 TDD 微循环:测试 -> 实现 -> 重构 -> 测试 …


第二,强化了模块与接口的概念。再纷繁复杂的业务逻辑也能按功能、层级分为若干业务模块,模块与模块之间通过接口(API)通信,做好这两点的设计无形中也就降低了业务逻辑的耦合性,低耦合又是单元测试的前提条件。这样操作等同于迫使开发者将接口的设计与低耦合性放在第一位去考虑。工作中在接到项目、明确需求后,如何分配任务往往非常考验团队人员的综合能力,拆解颗粒度太粗容易造成边界不明确;太细又牵扯过多精力,不易实施。但无论怎样,模块化和明确的接口设计是任务拆解得以顺利实施的前提,对将来可能发生的重构也是极好的。

第三,有利于任务的并行展开。当任务拆解分配到个人后,必然有些逻辑是需要前提输入条件的,比如客户端需要请求服务器,那么在编写测试用例时就应当提供这样的前提条件模拟,即 Mock 对象。目前流行的测试框架都带有 Mock 组件,比如谷歌的 GTest/GMock。有了这些交互对象,无论处在业务流程的哪个阶段,都可以马上展开任务,随时与上下游模块进行联调,同时利用各自的单元测试划分 Bug 归属。如果这一步不提前进行,开发任务就要按顺序进行,难免出现人员等待的情况。

第四,可以非常高效地进行重构。说起重构,可以说稍大点的项目,因为需求的变化或者逻辑的更新,重构在所难免。有些人就会心里发怵,生怕会引入新的 bug,甚至陷入重构的泥潭。如果这时有了事前准备好的测试用例,每重构完一块查看一下测试结果,就可化风险于无形。

此外 TDD 还很多优点,如快速反馈,测试用例即文档,降低测试团队负担等等。聊完了优点,接下来再看看网上大咖们对 TDD 的负面情绪都有哪些。

目前来看最集中的抱怨就是 TDD 会增加时间的投入。TDD 的优势是建立在高质量测试用例这一前提下的,如果测试代码写的不够好或者不够全面就难以覆盖所有功能点,而“测试 -> 实现 -> 重构”的微循环也会带来不少测试代码的开发工作。对于新手来讲,耽误了时间,效果却很有限,自然动力不足。即便是有信心能使用好 TDD 的团队,很多时候它的付出回报比也依然不高,尤其在强调迭代速度的互联网公司,根据时间、质量、花费三者只能取其二的理论,多数情况下也只能舍弃一部分质量来保证研发速度,何况有经验的团队即使不用 TDD 也是能保证质量损失在可控范围内的。

其他的抱怨来自 TDD 的规则太教条化,比如它的三大定律:

1. 在编写不能通过的单元测试前,不可编写生产代码。

2. 只可编写刚好无法通过的单元测试,不能编译也算不通过。

3. 只可编写刚好满足以通过当前失败测试的生产代码。

这一点关键看怎么理解,有个博主说的就很好 “Learn the rules, THEN break them.” 一旦理解了定律所表达的真实含义,是可以根据实际情况灵活变通的。

下面来谈谈个人对 TDD 一些肤浅的看法。

既然 TDD 是软件工程的一种理论方法,那么就会有它的适用范围,短平快的任务应用空间不会太大,TDD 更适合一些大中型、需要长期维护的项目,最好团队中能有 TDD 经验的人带领,如果没有可以去看看网上一些著名的开源项目是怎么编写它的测试代码的,学习高手写的代码,每看一次都非常受益。

另外极限编程的一些理念,比如 KISS(Keep It Simple, Stupid),YAGNI(You Aren’t Gonna Need It)与 TDD 结合起来也很值得玩味。这也不难理解,XP 和 TDD 本来就是一个人提出的理论。无论写代码还是写测试用例,这些原则性的东西,最好能贯彻。

最后再说一些编程方面的经验吧,最近这个项目给我印象最深的就是断言的使用。不仅是在测试用例中用来判断结果与期望值是否相符,更多是要在程序的关键位置埋好断言,将风险扼杀在摇篮之中。比如开源代码 WebRTC 在核心类的方法中就大量使用了断言,判断调用线程是否正确,关键值是否符合要求等。这类错误可能会在程序运行到后面某个点才暴露出来,相同原因导致的现象多种多样,如果不及时发现,会大大增加 Debug 的成本。

所以我的建议就是断言要大胆的加,甚至允许在 Release 版本中的关键位置存在断言,这样用户在反馈问题时,就能正确归因,及时解决改进。

【融云分析】基于 AVFoundation 框架开发小视频功能的方案解析

科技创新张改红 发表了文章 • 0 个评论 • 56 次浏览 • 2020-06-16 18:20 • 来自相关话题

开发视频录制功能最简单的就是使用系统封装的 UIImagePickerController,但是这种方式比较封闭,可自定义东西比较少,所以就需要基于 AVFoundation 框架来开发视频录制功能。基于 AVFoundation 框架来开发视频录制,比较复杂... ...查看全部

开发视频录制功能最简单的就是使用系统封装的 UIImagePickerController,但是这种方式比较封闭,可自定义东西比较少,所以就需要基于 AVFoundation 框架来开发视频录制功能。

基于 AVFoundation 框架来开发视频录制,比较复杂,需要自己手动设置设备音频,视频输入,输出。

AVCaptureSession 是 AVFoundation 的核心类,用于管理捕获对象 AVCaptureInput 的视频和音频的输入,协调捕获的输出 AVCaptureOutput。AVCaptureOutput 的输出有两种方法:一种是直接以 movieFileUrl 方式输出;一种是以原始数据流 data 的方式输出,流程对比图如下:


下面详细讲解两种录制视频的方案:

(1)AVCaptureSession + AVCaptureMovieFileOutput

创建 AVCaptureSession

注意:AVCaptureSession 的调用是会阻塞线程的,建议单独开辟子线程处理。

设置音频、视频输入

设置文件输出源

4.添加视频预览层


5.开始采集


6.开始录制


当实际的录制开始或停止时,系统会有代理回调。当开始录制之后,这时可能还没有真正写入,真正开始写入会回调下面代理,停止录制也是如此,所以如果你需要对录制视频起始点操作,建议通过系统的回调代理:


7.停止录制


8.停止采集


(2)AVCaptureSession + AVAssetWriter

1.创建 AVCaptureSession


2.设置音频、视频输入


3.设置音频 data、视频 data 输出


4.添加视频预览层


5.开始采集


和第一种方式不同,第一种方式是开始录制之后,movieFileOutput 的回调才会触发,停止录制回调触发之后也就完成了。AVCaptureSession + AVAssetWriter 方式因为在设置输出源的时候,把输出代理 (setSampleBufferDelegate)已经设置好了,所以一旦开始采集(startRunning),数据流回调也就触发了。


6.开始录制

这里需要创建AVAssetWriter,配置音频、视频录制参数,录制写入过程要单独开辟线程处理,避免阻塞线程,可以和 AVCaptureSession 放在同一线程处理。


7.处理数据流

开始采集,数据流就会回调,所以这里用了变量 isRecording 来界定当前是否需要对数据处理,一般是在 startRecord 和 stopRecord 才会去处理数据流。


8.停止录制


9.停止采集


两种方案对比:

相同点:他们的数据采集都是通过 AVCaptureSession 处理,音频视频的输入源也是一致的,画面预览一致。

不同点:输出源不一样,前者输出是 fileUrl,也就是说在视频写入完成之前开发者无法操作处理;后者输出是 data,AVAssetWriter 需要拿到 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 两个单独的输出,然后分别处理再写入指定路径。输出方式不同,决定了开发者对视频处理剪裁压缩的方式也就不同,前者如果需要对视频剪裁压缩,就需要从本地取出完整的视频文件,再做处理;而 AVAssetWriter 拿到的是数据流 data,如果需要剪裁压缩,可以直接配置相关参数后处理数据流,这样写入本地的就是已经处理过的视频文件。

其他功能点扩充

1.聚焦处理


2.摄像头切换


手机端看不到自己发的消息

回复

IM即时通讯admin 回复了问题 • 1 人关注 • 1 个回复 • 208 次浏览 • 2020-11-05 14:24 • 来自相关话题

【融云分析】SDK 交付质量保障之自动化测试

IM即时通讯融云那些事 发表了文章 • 0 个评论 • 197 次浏览 • 2020-07-24 12:29 • 来自相关话题

² 自动化测试的意义很多测试人员说到自动化测试领域,反应就是的接口自动化、Web 自动化、APP 自动化、Selenium、Appium 等等。其实这些都是针对于测试工作,用来解决问题时已经比较成熟的工具或方案,相信随着自动化领域的发展,对应自动化测... ...查看全部

² 自动化测试的意义

很多测试人员说到自动化测试领域,反应就是接口自动化、Web 自动化、APP 自动化、Selenium、Appium 等等。其实这些都是针对于测试工作,用来解决问题时已经比较成熟的工具或方案,相信随着自动化领域的发展,对应自动化测试工具,方案也会越来越丰富。

相对于手工测试而言,自动化测试本质上是使用代码或者工具,把复杂的测试工作从手动转化成为机器自动执行。优秀的框架、工具可以借鉴使用,但不要过于局限于现有工具和框架,而应根据自身产品特性和架构特性,寻找适合当前产品的自动化测试解决方案才是合理的自动化测试。

² 融云自动化测试实践

以融云的业务为例,在融云实时音视频 SDK 的质量保证上,有大量的测试点需要关注,例如:噪声啸叫抑制、回声消除、清晰度、首帧速度、移动端性能、耗电量、流量控制、延时、丢包等。

除了上述音视频质量检测以外,对于一个 SDK 基础服务来说,还有些需要重点关注的指标就是连通率指标,连通速度指标。而且该指标想达到 99.9% 以上的标准,那么针对每个功能修改,版本发布,测试次数需要数千次数万次的成功连通测试才能验证。

一、保障实时音视频 SDK 质量应具备的条件

音视频 SDK 测试需要测试不同厂商的客户端设备,对 SDK 画面渲染、稳定性、视音频连通等各种表现情况。因此我们还需要在单元测试的基础上,引入移动端,web 端的自动化测试检查客户端的具体表现能力。

1. 测试框架及工具的整合,建立稳定的 UI 自动化测试脚本  

Appium & Selenium 作为测试框架,可以支持iOS,Android,Chrome,Firefox 等多种驱动。并且无需对测试应用做任何嵌入式的修改,开源社区也相对活跃,作为UI自动化测试是一个比较好的选择。Python + Pytest 作为快速开发的语言和单元测试框架,可以提升测试脚本整体开发效率。

下面是 Appium & Selenium 基本工作原理:

 自动化测试1_副本.png

 

接触过 UI 自动化的同学,很多都会觉得 UI 自动化测试相对于接口、单元测试来说并不稳,尤其是遇到长时间运行几十个小时、几千上万条用例时,稳定性阻碍使用的一大难题,我们针对一些经常出现的问题进行解决。

 

元素不定期出现变化

对于元素不定期变化的问题,与团队进行沟通协调当然必不可少,也是最容易解决问题的方法,当然还有很多其他方式。

 

Page Object 设计模式对于 UI 测试来说就是一个不错的选择,Python3 有个升级就是全面 Unicode化,就是可以使用用中文命名变量,对于页面静态变量这种元素修改、查错来说效率还是可以提高不少。例如:

自动化测试2_副本.png


设备断开 & 网络异常

设备断开这个应该是阻断 UI 自动化常出现的问题了,数据线闪断、客户端服务 Crash、远程连接网络异常等,这时候重连机制就尤为重要了。针对这个问题我们可以给每个用例加增加装饰器函数如果用例失败并且检测到断开则立即重连;也可以用 Pytest 内置钩子函数使用方法检测断开重连,示例:

 自动化测试3_副本.png 

 

意外弹窗问题

很多厂商设备在你运行用例的时候,经常会弹出个窗口,这是非常头痛的,但是基本上所有的弹出按钮都是 Android: //android.widget.Button,iOS: //XCUIElementTypeButton 两种类型的 xpath。因此我们只需要在报错时,获取页面上所有这两种类型的文本处理一下即可,尽量不堵塞后续用例的运行。简单示例:

 自动化测试4_副本.png

 

良好的测试用例设计

无论是从事何职的测试人员,测试用例设计都应该是关注的重点,一个好的自动化测试用例设计可以发现更多的问题,也可以让用例运行更加稳定。

 

2. 提供多样丰富的测试数据,不放过每一次问题

在我们运行自动化测试时,检测到崩溃、黑屏、绿屏、花屏等异常错误的时候,需要尽可能地提供详细测试报告数据才能更加准确地定位问题。

 

移动端关键错误截图和日志

自动化测试的报错截图,比较好获取,但是日志内容是客户端查询的关键。ADB 或者 idevicesyslog 等工具虽然可以获取到手机日志,但是在脚本运行过程中,不容易精确定位并截取到测试用例开始到结束这段时间日志内容。

 

实际上 Appium 会自带日志缓冲区,在脚本运行的时,Appium 工具将移动端日志写入日志缓冲区。但是Appium 并没有提供 API 修改缓冲区大小,也无法筛选关键日志,因此我们针对 appium-xcuitest-driver、appium-android-driver、appium-adb 等库进行了符合自己产品需求的修改,可以进行日志过滤筛选主动触发清理缓冲区,使定位问题更加精确,测试报告更加完善。

 

移动端关键错误网络抓包

遇到错误时,网络交互数据也是检查错误的重要数据,我们需要利用 Wireshark 工具进行抓包截取部分网络抓包数据,针对 iOS 设备可以用 rvictl 命令 生成虚拟网卡,Android 设备则需要使用共享 Wifi 模式。之后利用 Wireshark  dumpcap 指定网卡和筛选数据。同日志抓取一样,通过钩子函数我们在用例开始和结束时精确地定位到错误区间,并将抓包数据添加到测试报告中,提供给相关人员排查依据。

3. 测试任务调度平台

测试平台有主要分发测试任务和运行自动化测试任务两种。我们希望测试人员无需部署任何环境或者进行简单部署,就可以快速接入平台运行自动化测试,查看测试报告。不需要限定固定的移动设备来连接在固定机器上执行自动化测试。

 自动化测试5_副本.png


上图我们针对 Android 可以使用 ADB server 服务器。自动化测试测试脚本 Appium 服务器利用 ADB 传输协议,通过局域网链接子节点 Agent 服务进行测试,这样可以让设备不受限制,连接局域网任意本人或者空闲电脑,运行子节点 Agent 即可立即运行自动化测试,空闲设备利用起来,我们就有了庞大的测试机器群了,使设备即插即用使用率最大化。

 

但是 iOS 系统特性限制,虽然有 WiFi 共享模式,但使用起来稳定性并不友好。因此需要在 MAC Agent机器上环境部署本地的 Appium 等相关服务,设备直连该机器通过平台执行自动化测试

 

二、移动端 IM SDK,要做到接口全覆盖测试

客户端 SDK 是为第三方开发者提供的软件开发工具包,工具包的形式集成在 App 内,一个 App 内可能包含了多个 SDK 工具包。一个 SDK 对外发布后,我们可以建议开发者如何调用 SDK,但是无法预计开发者怎样调用 SDK 的接口。因此一个稳定的 SDK 工具包就显得尤为重要。

 

SDK 接口要做到全字段校验才能保证稳定性。

SDK 测试方法中,单元测试虽然可以更加的高效和稳定,但是单元测试无法轻松地在不同的设备范围运行,也无法针对打包集成后 SDK 包的功能进行检测,从而无法检测 SDK 在各大应用设备上的集成表现以及开发者在集成时候所遇到的问题。

 

 

IM SDK 自动化测试解决方案。

做自动化测试,主要解决的问题是:

1) 核心通信能力尽可能的脱离 UI 自动化测试,做到快速迭代的能力;

2) 可以任意对 SDK 接口字段进行自由组合校验;

3) 可以测试覆盖单设备多应用测试场景。

 自动化测试6_副本.png

 

由上图可看出基本结构并不复杂,主要是根据约定 JSON 格式和 Demo 层中的 Server 进行通信,Server Demo 通过反射或者自定义等方式调用 IM SDK 的接口,这样使我们可以对SDK 的接口参数进行自由的组合,从而验证 SDK 在复杂的测试用例中,是否能保证产品质量的稳定性和异常参数回调的友好提示等。

 

打包后的IM SDK 自动化测试,使移动端 IM SDK 基础服务不再只依赖于 UI 层的 Demo 测试,可测试范围和版本回归效率能提升数十倍。

² 自动化测试的测试成本&预期收益平衡

 

软硬件行业自动化趋势在近年来愈发明显,当然自动化测试也随之一步步更加成熟,但是要做自动化测试,肯定要考虑测试成本和预期的收益。

 

虽然自动化测试可以在任何时候都可以自动运行,看似节省了时间,但是需要考虑到自动化脚本前期开发的时间成本和后期脚本的维护成本,而且自动化效率较为依赖用例设计,自动化测试用例的开发工作量有时会比手工测试的工作量还要大。项目开发周期短、业务新、测试业务主观性很强等类型的产品要慎重考虑。

 

自动化测试能带来哪些收益也是大家最关心的,自动化测试一个重要的特性就是一致性,它不会随着时间增长出现由于人的疲劳所带来的漏测、漏记,可增加版本发布的信任。由于测试是自动执行的,所以执行过程中极少会出现疏忽错误,当然这也取决于自动化测试脚本的设计质量。

 

在立项初期如果考虑使用自动化测试,一定要考虑清楚自动化测试目标是什么,用自动化测试来解决什么问题,如果想用自动化测试来节省人力成本显然是不合适的,自动化测试的首要目标应当是如何提高产品的质量。

 

以上就是融云在自动化测试实践中的一些所感所得,我们将其记录和整理,并与大家分享,也欢迎更多的技术小伙伴与我们一起探讨。

 

点击查看原文


 最新活动推荐:

融云年中大促活动海报.png


【融云分析】苹果 iOS 通知推送机制全面解析

IM即时通讯融云那些事 发表了文章 • 0 个评论 • 245 次浏览 • 2020-07-17 15:50 • 来自相关话题

在当下的 App 开发中,通知功能已成为不可或缺的一部分,目前主要分为两种模式:本地通知和远程推送。本文将围绕这两种模式,为开发者们详细介绍下 iOS 通知推送机制。本地通知一、本地通知介绍指定推送时间,该时间在手机上弹出推送通知,不需要网络连接,例如日历、待... ...查看全部

在当下的 App 开发中,通知功能已成为不可或缺的一部分,目前主要分为两种模式:本地通知和远程推送。本文将围绕这两种模式,为开发者们详细介绍下 iOS 通知推送机制。

本地通知

一、本地通知介绍

指定推送时间,该时间在手机上弹出推送通知,不需要网络连接,例如日历、待办、闹钟等应用。

更多详情请点击 ☞ Scheduling and Handling Local Notifications 

二、本地通知使用

1. 在代码中注册本地通知

如果是 iOS 7 及之前的设备,不需要开发者添加代码即可使用(用户需要打开 App 通知)。 

如果是 iOS 8 – iOS 10 之间的设备,直接用下方代码(通过注册本地通知)注册即可。 

如果是 iOS 10 以上的设备,需要在 Appdelegate 中导入 #import <UserNotifications/UserNotifications.h>,并遵循 UNUserNotificationCenterDelegate(在 iOS 10 中,苹果针对远程推送和本地通知推出了全新的 UserNotifications 框架),如下:

2. 发送本地通知

3. 取消本地通知

4. 处理收到的本地通知

4.1 应用处于前台运行状态

4.2 应用处于后台活跃状态

4.3 应用处于后台暂停或者被杀死状态


远程推送

一、远程推送介绍

更多详情请点击 ☞ APNs Overview

Provider:App Server

APNs:Apple Push Notification Service

远程推送工作流程

二、远程推送类型

1. 普通推送

服务端通过 APNs 推送到手机的一种消息通知,包括:声音、横幅、角标和自定义字段。

通知内容格式如下:

2. VoIP 推送

更多详情请点击 ☞ Voice Over IP (VoIP) Best Practices 

iOS 8 之后推出,依赖 PushKit.framework,主要用于音视频通话时响铃,VoIP 推送可以在应用被杀死的情况下唤醒 App。

使用时需要在 Signing & Capabilities 的 Background Modes 中打开 VoIP、Background fetch 和 Remote notification,并添加 PushKit.framework。

从 iOS 13 开始苹果为防止 VoIP 推送被非来电功能滥用,禁止在非来电功能中使用 VoIP 推送,如果使用 VoIP 推送只能使用 iOS 系统的 CallKit.framework 库,如果不使用 iOS 系统的 CallKit.framework 库,App 在收到 VoIP 推送后会被杀掉,表现上就类似于没有收到 VoIP 推送;由于苹果限制中国区域使用 iOS 系统的 CallKit.framework 库,导致 VoIP 推送功能也无法在苹果商店审核通过,可以将 VoIP 推送转成 APNs 解决,融云 iOS 13 以上 VoIP 功能适配

3. 静默推送

iOS 7 版本之后推出的一种特殊远程推送,又称为后台远程推送。这一推送的特征是收到通知时没有弹窗、横幅和声音,这时不用点开通知,不用打开 App 就会执行下面的方法:

注:1. 需要开启 Remote notifications 和 开启远程推送功能 

2. 静默推送的字段中不允许携带 alert、badge 和 sound 等字段,必须包含 content-available。

三、iOS 远程推送配置

1. 申请证书及配置文件

1.1 创建 App ID

1.1.1 登录 Apple Developer,进入 Identifiers,点击“+”按钮。

1.1.2 创建 App ID(如果 App ID 已经存在可以直接跳过此步骤)

注: App 的 BundleID 不能使用通配符,否则将无法使用远程推送服务。

1.1.3 开启远程推送服务

1.2 创建推送证书

1.2.1 创建 Push 证书

1.2.2 选择新建的证书类型(开发或者生产)

注:从 iOS 9.2 开始,Apple Developer 上生成的生产环境推送证书,名称为 Apple Push Services: XXX, 之前生成的生产环境推送证书名称为 Apple Production IOS Push Services: XXX。

1.2.3 选择要开启远程推送的 App ID,点击 Continue 后会提示需要一个 CSR 文件,CSR 文件需要参考 1.2.4 生成

1.2.4 生成 CSR 文件,用于上传

•打开 Mac 系统自带的钥匙串访问;

•从证书颁发机构请求证书;

•将请求的 CSR 保存到磁盘。

1.2.5 上传 Certificate Signing Request(CSR) 文件

将 1.2.4 中生成的 .certSigningRequest 文件上传,点击 Continue 即可生成推送证书。

1.2.6 下载生成的推送证书,并导出 .p12 文件

双击下载的推送证书,系统会将其导入钥匙串中。打开钥匙串访问,选中对应的证书,右键选择导出。保存 .p12 文件时,可以为其设置密码,也可以不设置密码。

注意右键选择导出的时候不要打开证书,直接在证书上点击右键即可。

1.3 创建配置文件

1.3.1 创建 Profiles

1.3.2 选择对应环境

1.3.3 为配置文件关联 App ID

1.3.4 选择开发者证书

1.3.5 选择要安装的设备

1.3.5 填写 Profile Name

1.3.6 下载后双击,即添加到 Xcode 中

2. 代码处理

2.1 在代码中注册远程推送

如果是 iOS 10 以上的设备,需要在 Appdelegate 中导入 #import <UserNotifications/UserNotifications.h>,并遵循 UNUserNotificationCenterDelegate(在 iOS 10 中,苹果针对远程推送和本地通知推出了全新的 UserNotifications 框架),如下:

#if __IPHONE_10_0

#import <UserNotifications/UserNotifications.h>

#endif

注册远程推送相关代码:

2.2. 处理 deviceToken

如果处理 deviceToken 的方法是通过去掉 [deviceToken description] 的 “<“、”>” 和 “空格” 的话,iOS 13 之前的设备可以获取到正确的 deviceToken,但是在 iOS 13 之后就无法获取正确的 deviceToken;因为 iOS 13 之后通过 [deviceToken description] 获取到的字符串变成了下面这样的格式:

现在应该采用的获取 deviceToken 的方法:

3. 处理收到的远程推送

3.1 应用处于前台运行状态

App 前台可见时,处于前台状态。

3.1.1 收到远程推送会回调下面的方法

3.1.2 点击远程推送会回调下面的方法

3.2 应用处于后台活跃状态

当 App 进入后台未被系统回收时,处于后台活跃状态。

3.2.1 点击弹窗会启动应用并回调下面的方法

3.3 应用处于后台暂停或者被杀死状态

当 App 进入后台被系统回收或者被杀进程,处于后台暂停状态。

四、iOS 远程推送扩展

1. 修改通知内容

利用 iOS 10 新增的 Notification Service Extension 可以修改收到的远程推送内容。

注意:

1.1 只在 iOS 10 以上有效;

1.2 后台推送过来的数据要协商好格式;

1.3 Targets 中的 Service Extension 的系统版本需要修改为 10.0,如果版本高于测试设备的系统版本,则不会走对应的方法。

具体步骤如下:

•给工程添加一个 target :Notification Service Extension。

•主工程开启 Push Notifications 和 Background Modes 功能。

•Service Extension target 开启 Push Notifications 功能。

•NotificationService.m 中实现 – (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler :

【融云分析】关于测试驱动开发(TDD)的感悟

科技创新张雷 发表了文章 • 0 个评论 • 58 次浏览 • 2020-06-16 18:26 • 来自相关话题

提起测试驱动开发(以下简称“TDD”),圈内工程师对其都有一定程度的了解,TDD 的优点也得到了普遍的认可。有研究机构曾对微软和 IBM 的八个开发小组进行了对照测试,结果发现使用了 TDD 的小组比未使用的小组在问题发生比例上减少了四至九成。在结对编程的相关... ...查看全部

提起测试驱动开发(以下简称“TDD”),圈内工程师对其都有一定程度的了解,TDD 的优点也得到了普遍的认可。有研究机构曾对微软和 IBM 的八个开发小组进行了对照测试,结果发现使用了 TDD 的小组比未使用的小组在问题发生比例上减少了四至九成。在结对编程的相关实验中,使用 TDD 的小组比未使用的小组在黑箱测试通过率上平均高出 18%,效果相当明显。

但反观日常所接触的实际工作中,对于 TDD 的使用并不多见,码农们对其价值也褒贬不一,网上甚至有大咖写文章公开论述观点来反对它,这又是为什么呢?前不久我刚好在融云的一个项目里小范围实践了一把,我就试着结合各方观点,斗胆谈谈自己的体会。

首先介绍一下什么是 TDD,TDD 最早是由 Kent Beck 提出并在他的《Test-Driven Development By Example》一书中进行详细阐述的(Kent Beck也是极限编程 Extreme Programming 概念的提出者)。书中所述:TDD 就是以测试作为开发过程的中心,要求编写任何产品代码之前,首先编写用于定义产品代码行为的测试,而编写的产品代码又要以使测试通过为目标的软件工程方法,目的是构造简单、清晰、高质量的代码。

测试是保证软件质量的重要手段,一个公司的研发部门通常都会有很大比例的测试团队作为质量保证的坚实后盾。那么作为开发人员是不是就可以只关心写代码的进度,编译通过后再跑几遍没问题就提交代码呢?这样的程序在碰上初始条件稍有改变,或者压力、并发等外部因素略有变化下会不会出现崩溃等问题呢?有的团队会制定规章制度,要求给完成的代码编写测试用例,必须通过才可以提交。这或许能在一定程度上使情况得到改善,但实际效果真的有那么明显么?我就听过有人抱怨说,完成代码后再写测试用例是浪费时间,因为对逻辑走向已十分了解,测试自然不会有什么大的纰漏,有那个时间不如多写几行代码,反正有测试团队兜底。乍一听似有道理,但仔细一想实则是在逃避责任,也在浪费公司资源。

那保证软件质量,有何良策呢?让我们来看 TDD 是如何做的,前面说过 TDD 的精髓在于将测试前置,这看似微不足道的变化到底会带来怎样的化学反应呢?

第一,能够明确目的。在动手编写生产代码之前,就得先想好这一部分逻辑的输入输出是什么,编写满足需求的测试用例,同时增加对需求的强化理解。举个简单的例子,与合作开发的同事对好需求,划分好各自实现的逻辑块,结果后续联调时才发现一方理解错了意思,之前的工作量就白费了。有了这提前编写的测试代码,就能逻辑层面再次明确目标,避免语言文字上的误解。在编写代码过程中,更容易做到心无旁骛,思绪不会乱飘,因为你的目标就是编写能通过测试用例的代码。当然这一过程可能会需要持续对测试目标进行完善,即所谓的 TDD 微循环:测试 -> 实现 -> 重构 -> 测试 …


第二,强化了模块与接口的概念。再纷繁复杂的业务逻辑也能按功能、层级分为若干业务模块,模块与模块之间通过接口(API)通信,做好这两点的设计无形中也就降低了业务逻辑的耦合性,低耦合又是单元测试的前提条件。这样操作等同于迫使开发者将接口的设计与低耦合性放在第一位去考虑。工作中在接到项目、明确需求后,如何分配任务往往非常考验团队人员的综合能力,拆解颗粒度太粗容易造成边界不明确;太细又牵扯过多精力,不易实施。但无论怎样,模块化和明确的接口设计是任务拆解得以顺利实施的前提,对将来可能发生的重构也是极好的。

第三,有利于任务的并行展开。当任务拆解分配到个人后,必然有些逻辑是需要前提输入条件的,比如客户端需要请求服务器,那么在编写测试用例时就应当提供这样的前提条件模拟,即 Mock 对象。目前流行的测试框架都带有 Mock 组件,比如谷歌的 GTest/GMock。有了这些交互对象,无论处在业务流程的哪个阶段,都可以马上展开任务,随时与上下游模块进行联调,同时利用各自的单元测试划分 Bug 归属。如果这一步不提前进行,开发任务就要按顺序进行,难免出现人员等待的情况。

第四,可以非常高效地进行重构。说起重构,可以说稍大点的项目,因为需求的变化或者逻辑的更新,重构在所难免。有些人就会心里发怵,生怕会引入新的 bug,甚至陷入重构的泥潭。如果这时有了事前准备好的测试用例,每重构完一块查看一下测试结果,就可化风险于无形。

此外 TDD 还很多优点,如快速反馈,测试用例即文档,降低测试团队负担等等。聊完了优点,接下来再看看网上大咖们对 TDD 的负面情绪都有哪些。

目前来看最集中的抱怨就是 TDD 会增加时间的投入。TDD 的优势是建立在高质量测试用例这一前提下的,如果测试代码写的不够好或者不够全面就难以覆盖所有功能点,而“测试 -> 实现 -> 重构”的微循环也会带来不少测试代码的开发工作。对于新手来讲,耽误了时间,效果却很有限,自然动力不足。即便是有信心能使用好 TDD 的团队,很多时候它的付出回报比也依然不高,尤其在强调迭代速度的互联网公司,根据时间、质量、花费三者只能取其二的理论,多数情况下也只能舍弃一部分质量来保证研发速度,何况有经验的团队即使不用 TDD 也是能保证质量损失在可控范围内的。

其他的抱怨来自 TDD 的规则太教条化,比如它的三大定律:

1. 在编写不能通过的单元测试前,不可编写生产代码。

2. 只可编写刚好无法通过的单元测试,不能编译也算不通过。

3. 只可编写刚好满足以通过当前失败测试的生产代码。

这一点关键看怎么理解,有个博主说的就很好 “Learn the rules, THEN break them.” 一旦理解了定律所表达的真实含义,是可以根据实际情况灵活变通的。

下面来谈谈个人对 TDD 一些肤浅的看法。

既然 TDD 是软件工程的一种理论方法,那么就会有它的适用范围,短平快的任务应用空间不会太大,TDD 更适合一些大中型、需要长期维护的项目,最好团队中能有 TDD 经验的人带领,如果没有可以去看看网上一些著名的开源项目是怎么编写它的测试代码的,学习高手写的代码,每看一次都非常受益。

另外极限编程的一些理念,比如 KISS(Keep It Simple, Stupid),YAGNI(You Aren’t Gonna Need It)与 TDD 结合起来也很值得玩味。这也不难理解,XP 和 TDD 本来就是一个人提出的理论。无论写代码还是写测试用例,这些原则性的东西,最好能贯彻。

最后再说一些编程方面的经验吧,最近这个项目给我印象最深的就是断言的使用。不仅是在测试用例中用来判断结果与期望值是否相符,更多是要在程序的关键位置埋好断言,将风险扼杀在摇篮之中。比如开源代码 WebRTC 在核心类的方法中就大量使用了断言,判断调用线程是否正确,关键值是否符合要求等。这类错误可能会在程序运行到后面某个点才暴露出来,相同原因导致的现象多种多样,如果不及时发现,会大大增加 Debug 的成本。

所以我的建议就是断言要大胆的加,甚至允许在 Release 版本中的关键位置存在断言,这样用户在反馈问题时,就能正确归因,及时解决改进。

【融云分析】基于 AVFoundation 框架开发小视频功能的方案解析

科技创新张改红 发表了文章 • 0 个评论 • 56 次浏览 • 2020-06-16 18:20 • 来自相关话题

开发视频录制功能最简单的就是使用系统封装的 UIImagePickerController,但是这种方式比较封闭,可自定义东西比较少,所以就需要基于 AVFoundation 框架来开发视频录制功能。基于 AVFoundation 框架来开发视频录制,比较复杂... ...查看全部

开发视频录制功能最简单的就是使用系统封装的 UIImagePickerController,但是这种方式比较封闭,可自定义东西比较少,所以就需要基于 AVFoundation 框架来开发视频录制功能。

基于 AVFoundation 框架来开发视频录制,比较复杂,需要自己手动设置设备音频,视频输入,输出。

AVCaptureSession 是 AVFoundation 的核心类,用于管理捕获对象 AVCaptureInput 的视频和音频的输入,协调捕获的输出 AVCaptureOutput。AVCaptureOutput 的输出有两种方法:一种是直接以 movieFileUrl 方式输出;一种是以原始数据流 data 的方式输出,流程对比图如下:


下面详细讲解两种录制视频的方案:

(1)AVCaptureSession + AVCaptureMovieFileOutput

创建 AVCaptureSession

注意:AVCaptureSession 的调用是会阻塞线程的,建议单独开辟子线程处理。

设置音频、视频输入

设置文件输出源

4.添加视频预览层


5.开始采集


6.开始录制


当实际的录制开始或停止时,系统会有代理回调。当开始录制之后,这时可能还没有真正写入,真正开始写入会回调下面代理,停止录制也是如此,所以如果你需要对录制视频起始点操作,建议通过系统的回调代理:


7.停止录制


8.停止采集


(2)AVCaptureSession + AVAssetWriter

1.创建 AVCaptureSession


2.设置音频、视频输入


3.设置音频 data、视频 data 输出


4.添加视频预览层


5.开始采集


和第一种方式不同,第一种方式是开始录制之后,movieFileOutput 的回调才会触发,停止录制回调触发之后也就完成了。AVCaptureSession + AVAssetWriter 方式因为在设置输出源的时候,把输出代理 (setSampleBufferDelegate)已经设置好了,所以一旦开始采集(startRunning),数据流回调也就触发了。


6.开始录制

这里需要创建AVAssetWriter,配置音频、视频录制参数,录制写入过程要单独开辟线程处理,避免阻塞线程,可以和 AVCaptureSession 放在同一线程处理。


7.处理数据流

开始采集,数据流就会回调,所以这里用了变量 isRecording 来界定当前是否需要对数据处理,一般是在 startRecord 和 stopRecord 才会去处理数据流。


8.停止录制


9.停止采集


两种方案对比:

相同点:他们的数据采集都是通过 AVCaptureSession 处理,音频视频的输入源也是一致的,画面预览一致。

不同点:输出源不一样,前者输出是 fileUrl,也就是说在视频写入完成之前开发者无法操作处理;后者输出是 data,AVAssetWriter 需要拿到 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 两个单独的输出,然后分别处理再写入指定路径。输出方式不同,决定了开发者对视频处理剪裁压缩的方式也就不同,前者如果需要对视频剪裁压缩,就需要从本地取出完整的视频文件,再做处理;而 AVAssetWriter 拿到的是数据流 data,如果需要剪裁压缩,可以直接配置相关参数后处理数据流,这样写入本地的就是已经处理过的视频文件。

其他功能点扩充

1.聚焦处理


2.摄像头切换