mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-24 20:00:37 +00:00
docs: 移动端质量保障
This commit is contained in:
108
Chapter1 - iOS/1.101.md
Normal file
108
Chapter1 - iOS/1.101.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# 离屏渲染
|
||||
|
||||
## 什么是离屏渲染
|
||||
如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的 Frame Buffer(帧缓冲区),作为像素数据存储区域,然后由显示控制器把帧缓冲区的数据显示到屏幕上。如果因为面临一些限制,比如阴影、光栅、遮罩等,CPU 无法把渲染结果直接写写入 Frame Buffer,而是先暂时把中间的临时状态保存在额外的内存区域,之后再写入 Frame Buffer,那么这个过程被称为离屏渲染。
|
||||
系统如果没有直接把渲染结果直接写入到 GPU FrameBuffer 中,则认为发生了一次离屏渲染。(离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作)
|
||||
|
||||
|
||||
## 哪些 case 会触发离屏渲染
|
||||
- 光栅化(shouldRasterize)
|
||||
属于系统的优化机制,当开启光栅化的时候,系统会将该图片以 BitMap 的形式缓存起来,缓存时间为100ms,当下次需要显示这张图片的时候,系统会从缓存中获取出这张图片传递给 GPU,不需要 GPU 再次渲染这部分图层,达到减少 GPU 运算量的目的。
|
||||
应用场景非常小,因为时间仅为100ms,且会触发离屏渲染。
|
||||
```
|
||||
self.imageView.layer.shouldRasterize = YES
|
||||
```
|
||||
- 遮罩(mask)
|
||||
遮罩 Mask 相当于增加了 GPU 绘制复杂度,无法一次计算完成,需要增加一块新的帧缓冲区计算。
|
||||
```
|
||||
CALayer *layer = [CALayer layer];
|
||||
layer.frame = // ...;
|
||||
self.imageView.layer.mask = layer;
|
||||
```
|
||||
- 阴影(shadow)
|
||||
因为阴影位于视图下层,绘制完阴影,界面还没有绘制完主要内容,所以需要一块额外的帧缓冲区中转。
|
||||
```
|
||||
self.imageView.layer.shadowColor = [UIColor redColor].CGColor;
|
||||
self.imageView.layer.shadowOpacity = 0.2;
|
||||
```
|
||||
如果给阴影设置 shadowPath 则不会触发离屏幕渲染。因为 shadowPath 预先告诉 CoreAnimation 框架阴影的几何形状,因此不需要依赖 layer 本体,可以独立渲染。
|
||||
- 抗锯齿(竖直图片旋转后会出现锯齿)
|
||||
可能会触发离屏渲染,假如 UIImageView 控件的尺寸和图片素材的大小不一致,比如设置旋转,则会触发离屏渲染,否则不会。
|
||||
抗锯齿的计算量很大,因此需要额外的帧缓冲区保存计算结果,则触发离屏渲染。
|
||||
```
|
||||
CGFloate angle = M_PI/60.0;
|
||||
self.iamgeView.layer setTransform3DRotate(self.imageView.layer.transform, angle, 0, 0, 1);
|
||||
self.iamgeView.layer.allowsEdgeAntialiasing = YES;
|
||||
```
|
||||
- 不透明
|
||||
当 alpha 为1的时候,不会触发离屏渲染。
|
||||
当 alpha 不为1的时候,且设置了父视图的 allowsGroupOpacity 为 YES,则会触发离屏渲染。因为父视图的 allowsGroupOpacity 为 YES,则代表子视图的透明度是否和父视图一样,一样则需要额外的帧缓冲区计算。
|
||||
```
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0, 10, 20)];
|
||||
view.backgroundColor = [UIColor redColor];
|
||||
[self.imageView addSubview: view];
|
||||
self.iamgeView.alpha = 1;
|
||||
self.iamgeView.layer.allowsGroupOpacity = YES;
|
||||
```
|
||||
- 圆角
|
||||
当给视图设置了背景颜色且设置了圆角,则会触发离屏渲染。
|
||||
UILabel 比较特殊,给 UILabel 设置 backgroundColor 其实就是给 UILabel 的 contents 设置背景颜色,contents 层级比 layer 高,所以 UILabel 整体显示为红色。
|
||||
下面显示结果为:红绿
|
||||
|
||||
```
|
||||
self.label.backgroundColor = [UIColor redColor];
|
||||
self.label.layer.backgroundColor = [UIColor greenColor].CGColor;
|
||||
self.label.layer.cornerRadius = YES;
|
||||
|
||||
self.iamgeView.backgroundColor = [UIColor redColor];
|
||||
self.iamgeView.layer.backgroundColor = [UIColor greenColor].CGColor;
|
||||
self.imageView.layer.cornerRadius = YES;
|
||||
```
|
||||
|
||||
## 离屏渲染的影响?
|
||||
离屏渲染,指的是 GPU 在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。由上面的一个结论视图和圆角的大小对帧率并没有什么影响,数量才是伤害的核心输出啊。可以知道离屏渲染耗时是发生在离屏这个动作上面,而不是渲染。为什么离屏这么耗时?原因主要有创建缓冲区和上下文切换。创建新的缓冲区代价都不算大,付出最大代价的是上下文切换。
|
||||
上下文切换,不管是在GPU渲染过程中,还是一直所熟悉的进程切换,上下文切换在哪里都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen Rendering 或者再开始一个新的离屏渲染重复之前的操作。
|
||||
|
||||
一次mask发生了两次离屏渲染和一次主屏渲染。即使忽略昂贵的上下文切换,一次mask需要渲染三次才能在屏幕上显示,这已经是普通视图显示3陪耗时,若再加上下文环境切换,一次mask就是普通渲染的n(n>3)倍以上耗时操作
|
||||
|
||||
正常流程:App Source Code -> CPU -> Frame Buffer -> Dispaly
|
||||
离屏渲染流程:App Source Code -> CPU -> Off Screen Frame Buffer -> Frame Buffer -> Dispaly
|
||||
## 如何优化?
|
||||
- 针对 shadow 可以增加 shadowPath
|
||||
- 针对圆角可以增加贝塞尔曲线或者一张图片实现(类似遮罩)。
|
||||
|
||||
## 特殊的离屏渲染
|
||||
- drawRect 是一种特殊情况,因为是依赖 Core Graphics 将绘制结果保存在 backing store 中,是 CPU 层面的操作,离屏渲染是 GPU 层面的。
|
||||
|
||||
1. 重写 drawRect 方法的时候系统会为该 View 创建一块内存区域,渲染结果先保存到该内存区域,最后将该内存区域的结果写入到 FrameBuffer 中,但是该现象不属于严格意义的离屏渲染。
|
||||
|
||||
## 画家算法
|
||||
画家算法,也叫做优先填充算法,是计算机三维图形学中处理可见性问题的一种解法(三维场景投影到二维平面上)。画家算法先将场景中的多边形按照深度进行排序,然后按照由远及近的顺序进行描述,这样可以将不可见的部分覆盖,解决“可见性”问题(也就是一层层画布进行绘制,最后叠加)。
|
||||
|
||||
GPU 利用片元将整个图片分为一个个像素,并且并行计算了每一个像素的颜色。在同一个栅格内可能存在多个视图,根据距离眼睛的远近,存在多个不同的物体。显而易见,我们应该将最近物体的颜色作为该栅栏的颜色,后面物体的颜色应该被遮挡(如果后面物体的颜色被传递给片元着色器,这时候就是一个显示错误,比如我们打游戏的时候可以看到墙后的人)
|
||||
|
||||
画家算法带来2个问题。第一个问题上相互交错的物体,按照画家算法,这样的情况,GPU 会无从下手。所以早期的时候,设计师总是避免这样相互交错的设计。
|
||||
第二个问题是过度绘制,因为画家算法总是一层层绘制,所以存在重合叠加的情况,层级较低的物体总是会被过度绘制,浪费资源。
|
||||
|
||||
因为 GPU 的设计是并发、无序的,所以我们期望的画家算法是不希望浪费、等待,同时为了绘制速度,所以在此基础上引入了 Depth Buffer 和 Early-Z 和深度缓冲。
|
||||
|
||||
画家算法有个缺点,就是当后面的图层开始渲染时,是无法回过头去处理之前的图层,这就对于一些前后依赖的图层时,无法实现,因此需要申请一块额外的帧缓冲区来完成,比如阴影、圆角。
|
||||
|
||||
明白了画家算法的工作原理,也就明白了为什么会发生离屏渲染。
|
||||
- 离屏渲染需要创建额外的帧缓冲区
|
||||
- 渲染相关的上下文对象、帧缓冲区都比较大,切换会带来性能损耗
|
||||
- 内存拷贝,需要将临时帧缓冲区的内容拷贝到真正的帧缓冲区
|
||||
单帧渲染都会比较耗费性能了,如果屏幕上多个视图渲染都存在离屏渲染,整个界面会发生卡顿。
|
||||
|
||||
|
||||
## 如何检测离屏渲染
|
||||
Xcode 就提供了检测功能,打开路径为: Xcode -> Debug -> View Debugging -> Rendering -> Color Offscreen-Renderer Yellow
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 引申阅读
|
||||
- [实时渲染管线中的光源渲染问题](https://zhuanlan.zhihu.com/p/392748735)
|
||||
- [蒙特卡罗方法](https://wiki.mbalib.com/wiki/蒙特卡罗方法)
|
||||
- [抗锯齿方法](https://zhuanlan.zhihu.com/p/56385707)
|
||||
@@ -11,10 +11,9 @@
|
||||
5. 范围编辑。多光标是个很棒的并且每个高级的编辑器都该有的特训过,快捷键为**Command+Control+E**。将光标移动刀需要编辑的符号,输入快捷键,然后就可以在当前页面全局编辑了。
|
||||
|
||||
6. Xcode 设置代码只在 Debug 下起效的几种方式
|
||||
在日常开发中 Xcode 在 Debug 模式下写很多测试代码,或者引入一些第三方测试用的 .a 和 .framework 动态库,也会通过 CocoaPods 引入一些第三方测试工具或者库;但是不希望这些库在**Release**正式包中被引入,如何做到呢?
|
||||
|
||||
在日常开发中 Xcode 在 Debug 模式下写很多测试代码,或者引入一些第三方测试用的 .a 和 .framework 动态库,也会通过 CocoaPods 引入一些第三方测试工具或者库;但是不希望这些库在**Release**正式包中被引入,如何做到呢?
|
||||
* .h/.m 文件中的测试代码
|
||||
|
||||
|
||||
Xcode 在 Debug 模式下定义了宏 DEBUG=1 ,所以我们可以在代码中把相关的测试代码写在预编译处理命令 **\#ifdef DEBUG... \#endif** 中间即可,如图所示
|
||||
|
||||

|
||||
@@ -22,74 +21,93 @@
|
||||

|
||||
|
||||
* 测试用的 .a 和 .framework
|
||||
|
||||
|
||||
对于拖拽到工程中的 .a .framework 静态库,可以在 **target->Build Settings->Search Paths**这2个选项,分别设置 **Library Search Paths**和**Framework Search Paths**这2个选项。如果我们需要在测试的时候会用到,那么我们可以将 **Debug** 对应的值留下,删掉**Release** 对应的值。这样我们打包 Release 包的时候就不会包含不需要的包。
|
||||
|
||||
|
||||

|
||||
|
||||
* CocoPods 引入的库
|
||||
对于 CocoPods 方式引入的库,在配置的时候就可以处理掉,比如下面的方式
|
||||
|
||||
```
|
||||
platform: iOS, '8.0'
|
||||
...
|
||||
pod 'PonyDebugger', :configurations => ['Debug']
|
||||
```
|
||||
|
||||
7. App Store Connect 经常在上架的时候需要开发人员判断是否满足出口合规的证明,每次写都很麻烦,所以可以在工程里面的 plist 里面进行设置。
|
||||
```
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
```
|
||||
|
||||
```
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
```
|
||||
|
||||
8. 让 Xcode 折叠代码
|
||||
在 VS Code 或者其他 IDE 里面都具有代码折叠的功能,Xcode 也支持代码折叠功能,但是默认没有开启。所以我们需要做的就是打开代码折叠功能。步骤:打开 Xcode - Preference - Text Editing - 在「Show」模块下面勾选「Code folding ribbon」。这样 Xcode 就具备代码折叠的功能了。
|
||||
快捷键:
|
||||
在 VS Code 或者其他 IDE 里面都具有代码折叠的功能,Xcode 也支持代码折叠功能,但是默认没有开启。所以我们需要做的就是打开代码折叠功能。步骤:打开 Xcode - Preference - Text Editing - 在「Show」模块下面勾选「Code folding ribbon」。这样 Xcode 就具备代码折叠的功能了。
|
||||
快捷键:
|
||||
- command + option + 左右方向键 : 折叠或展开鼠标光标所在位置的代码
|
||||
- command + option + shift + 左右方向键:折叠或展开当前页面全部的方法(函数)
|
||||
|
||||
|
||||
9. 几种设置废弃 Api 的方法
|
||||
|
||||
- __deprecated
|
||||
|
||||
|
||||
- NS_UNAVAILABLE。`- (instancetype)init NS_UNAVAILABLE;`
|
||||
|
||||
|
||||
- #define MJRefreshDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
|
||||
|
||||
```
|
||||
MJRefreshDeprecated("请使用automaticallyChangeAlpha属性");
|
||||
```
|
||||
|
||||
- DEPRECATED_ATTRIBUTE
|
||||
|
||||
```
|
||||
@property (nonatomic, strong, readonly) UILabel *dateLabel DEPRECATED_ATTRIBUTE;
|
||||
```
|
||||
|
||||
- DEPRECATED_MSG_ATTRIBUTE
|
||||
```
|
||||
|
||||
```
|
||||
@property (nonatomic, assign) NSStringEncoding stringEncoding DEPRECATED_MSG_ATTRIBUTE("The string encoding is never used. AFHTTPResponseSerializer only validates status codes and content types but does not try to decode the received data in any way.");
|
||||
```
|
||||
|
||||
- @property(nullable, nonatomic, strong) IBOutlet NSLayoutConstraint *IQLayoutGuideConstraint __attribute__((deprecated("Due to change in core-logic of handling distance between textField and keyboard distance, this layout contraint tweak is no longer needed and things will just work out of the box regardless of constraint pinned with safeArea/layoutGuide/superview.")));
|
||||
|
||||
- + (CLLocationDistance)getCurrentLocationDistanceFilter __deprecated_msg("废弃方法(空实现),使用distanceFilter属性替换");
|
||||
|
||||
|
||||
- + (NSString *)getWeiboAppSupportMaxSDKVersion __attribute__((deprecated));
|
||||
|
||||
- #pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
- #pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
10. Xcode Instruments 内存泄漏检测工具 Leaks 在内存检测后,无法看到具体的堆栈信息。
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
涂上右下方的 `Heaviest Stack Trace` 模块看不到对应的堆栈信息。一番定位问题后发现是工程项目在 debug 阶段,Build Setting 中的 **Debug Information Format** 选项的 debug 条目是没有 dSYM 文件的,我们要想看到堆栈信息,就必须选择 `DWARF with dSYM File` 选项。
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
DWARF,即 ***Debug With Arbitrary Record Format*** ,是一个标准调试信息格式,即调试信息。这部分信息可以查看我的[这篇文章](./1.74.md)中讲 iOS 符号化的部分。
|
||||
|
||||
11.
|
||||
11. 将 OC 代码还原为 C++ 代码
|
||||
|
||||
```objectivec
|
||||
// 方法1
|
||||
clang -rewrite-objc xxxx.m -o xxxx.cpp
|
||||
// 方法2
|
||||
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxxx.m -o xxxx.cpp
|
||||
```
|
||||
|
||||
12. 工程打开汇编,Debug 更多信息
|
||||
|
||||
菜单栏:Xcode -> Debug -> Debug Workflow -> Always Show Disassembly 可以查看汇编。
|
||||
|
||||
查看汇编可以从更深层了解当前函数的汇编层面的执行,为 objc 源码分析提供信
|
||||
息避免方向性错误,结合 memory read 可以更清楚的看到寄存器之间是如何互相配合
|
||||
处理配合的;使用汇编查看流程,可以在不确定源码出处和执行流程的情况下,跟踪内
|
||||
部代码,并可以找到出处!同时,结合下符号断点的方式,能够更清晰的跟踪源码实
|
||||
现。
|
||||
|
||||
13.
|
||||
@@ -1,4 +1,4 @@
|
||||
# App 质量把控
|
||||
# 客户端质量把控
|
||||
|
||||
> 笔者结合中台经验,本文重点谈谈 App 的质量稳定性该如何做。业务作为 App 的核心服务之一,业务异常监控当然也很重要,这不是本文重点。
|
||||
|
||||
@@ -86,3 +86,108 @@ QA 指派的测试用例一定要冒烟通过,冒烟打回很严重的,这
|
||||
|
||||
|
||||
|
||||
## SDK 质量 CheckList
|
||||
|
||||
- ChangeLog、Podspec、Readme 完善
|
||||
|
||||
- BetterMR +3 机制深入贯彻(一名角色为项目的另一端同学,另一名角色为本技术栈更资深的老司机)
|
||||
|
||||
- 冒烟通过率100%(假如技术项目、日常优化可以交叉测试)
|
||||
|
||||
- 精准测试,以及精准测试报告分析。代码行覆盖率至少80%
|
||||
|
||||
- 高铁包回归阶段:UI 自动化点击页面,发现性能(APM)与稳定性问题(Crash)、业务异常天网报警监控(之前都是忽略未上线前高铁阶段的质量问题的,提前感知问题提前修复,减少线上问题)
|
||||
|
||||
- 业务 SDK 正式发布阶段,业务线接入升级时,工程师需充当 QA 角色,评估业务影响面,数据需要全面评估(新老版本兼容性、灰度策略),产出 SDK 性能测试报告和影响面报告
|
||||
|
||||
技术 SDK 质量 CheckList
|
||||
|
||||
- ChangeLog、Podspec、Readme 完善,SDK 发布必须 Lint 通过
|
||||
|
||||
- BetterMR +3 机制深入贯彻(一名角色为项目的另一端同学,另一名角色为本技术栈更资深的老司机)
|
||||
|
||||
- 新开的 SDK 必须写单测,覆盖率90%以上
|
||||
|
||||
- 对于存量 SDK 可以通过 BDD 补充测试用例,不如 APM 卡顿测试,可以在10s内 Mock 3次卡顿。假设普通卡顿临界值为0.2s,严重卡顿为1s,ANR为5s,手动Mock3次卡顿,分别为0.3s、2s、6s,基于 BDD 我们可以对监控结果进行判断,比如断言抓到3次卡顿,其中2次严重卡顿、1次 ANR
|
||||
|
||||
- 开发阶段必须关心性能:内存、电量、卡顿、网络。用 Instrucments 测试
|
||||
|
||||
- 冒烟通过率100%(假如技术项目、日常优化可以交叉测试)
|
||||
|
||||
- 高铁包回归阶段:UI 自动化点击页面,发现性能(APM)与稳定性问题(Crash)、业务异常天网报警监控(之前都是忽略未上线前高铁阶段的质量问题的,提前感知问题提前修复,减少线上问题)
|
||||
|
||||
- 业务 SDK 正式发布阶段,业务线接入升级时,工程师需充当 QA 角色,评估业务影响面,数据需要全面评估(新老版本兼容性、灰度策略),产出 SDK 性能测试报告和影响面报告
|
||||
|
||||
|
||||
|
||||
## SDK 测试方法
|
||||
|
||||
客户端SDK是为第三方开发者提供的软件开发工具包,包括 SDK 接口、开发文档和 Demo 示例等。SDK 和应用之间的关系?以 IM 为例,App 调用 IM SDK 接口。进行客服消息功能模块的接入,也包括消息 PUSH 功能的使用方。包括 Weex、JS 等资源的更新、商品数据更新 PUSH 后端上的感知能力、智能经营消息等。
|
||||
|
||||
|
||||
### 客户端 SDK 测试的对象
|
||||
客户端 SDK 测试,就是对提供给开发者的工具包里面的内容进行测试
|
||||
|
||||
因此测试的主要内容有:
|
||||
1. SDK 接口和文档
|
||||
- SDK 接口是测试的主要对象,也是核心的内容
|
||||
|
||||
2. SDK 日志
|
||||
对开发者来说,SDK 接口里面的具体实现是透明的,当上层调用时遇到问题,只能依赖 SDK 打印的日志来定位分析。所以 SDK 日志是否完备,是否有助于解决问题,对应用开发者和 SDK 提供方来说都很重要
|
||||
|
||||
3. Demo 或行业解决方案
|
||||
Demo 测试可以看成是基于行为的测试。Demo 是SDK提供方用来示例如何调用接口实现具体的功能,也可以作为开发者直观感受SDK接入效果。行业解决方案类似 Demo,但是,比 Demo 更加像一个产品,具有比较完整和典型的行业应用场景。可以让行业开发者比较明确知道,接入这个 SDK 做出来的产品效果如何。
|
||||
|
||||
4. 其他周边
|
||||
比如UIkit等,可能只是在SDK开发中的附带输出,但对有的开发者来说能极大降低接入成本
|
||||
|
||||
### 客户端SDK接口测试类型
|
||||
客户端SDK根据需求和开发平台不同,可能需要选择不同的测试类型对SDK接口进行测试
|
||||
|
||||
常见的测试类型有:
|
||||
1. 功能测试
|
||||
保证 SDK 接口功能正确性和完备性。客户端 SDK 接口测试跟服务端接口测试类似,包括场景覆盖和接口参数覆盖
|
||||
主要测试各种参数组合下的返回值,考虑数据是否缓存与存储,是否有回调,对于请求成功或失败都能按预期进行处理
|
||||
|
||||
2. 性能测试
|
||||
保证 SDK 接口满足特定的性能需求,比如资源占用、移动设备耗电量等。比如 APM 在卡顿定制抓取堆栈的时候会对设备有内存和 CPU 的影响,如果全量抓取一次堆栈会更加耗时,如果异步抓取主线程堆栈。实现不好,很有可能在发生卡顿的时候,由于 APM 实现不好,导致本来的卡顿变成了 OOM。所以测试时就需要考虑这个场景的性能
|
||||
|
||||
3. 兼容性测试
|
||||
保证 SDK 兼容特定的设备平台,并与其他软件兼容。兼容设备平台的工作量通常是比较大的,先根据产品需求和市场现状对需要适配的设备平台做分析,再根据需要覆盖的机型、系统版本、分辨率等进行优先覆盖排序
|
||||
移动端 SDK 兼容性测试需要考虑下对模拟器的支持,因为很多开发者可能就是先在模拟器上开发。客户端 SDK 覆盖多平台设备的,还要考虑多端消息数据包的互通
|
||||
|
||||
4. 稳定性测试
|
||||
考察业务场景在一定压力下,持续运行一段时间,接口功能和设备资源占用有无异常。比如早期做 APM 时候,参考腾讯 Matrix 的代码,居然线上发生了 OOM,最后二分法排查代码改动,居然定位到了 CPU 利用率获取代码中,有 c 对象没有 free,所以代码的稳定性也是需要测试去考虑和关注的。
|
||||
|
||||
|
||||
5. 网络相关测试
|
||||
保证在不同网络类型,不同网络环境下,SDK 接口都能较好的处理。在涉及到多媒体资源或音视频通信,弱网下测试的需求较多,并且弱网下的处理通常需要反复优化和对比,不仅是新老版本效果对比,还包括竞品的效果对比测试
|
||||
|
||||
6. 安全性测试
|
||||
对隐私数据保护,访问权限的控制,用户服务鉴权等,SDK 接口的安全性问题也是比较突出。安全性很多是在架构设计和开发设计中就考虑进去,但是最好还是有专门的安全性测试
|
||||
|
||||
上述诸多测试类型中,功能测试先行。在进行客户端SDK测试前,需要全面的了解测试对象的细节:
|
||||
- 了解业务流程,结合API接口文档和开发指南,理顺接口的使用场景和调用关系;
|
||||
- 了解 SDK 协议,理解协议中字段的意义以及服务器端的处理逻辑;
|
||||
- 了解各接口或协议返回码,分析对应的场景;
|
||||
- 了解开发实现细节,可以绘制成图,便于测试分析和分层验证。
|
||||
|
||||
对客户端 SDK 进行测试,可以采用的分层测试方式由上至下依次有:基于 Demo 和解决方案->基于接口调用->基于代码。
|
||||
|
||||
1、基于 Demo 和解决方案的测试
|
||||
大多客户端SDK在提测时,都会有对应的Demo或者解决方案提交给测试,因此可以覆盖到该Demo或解决方案对应的接口或业务场景。而且测试人员可以比较直观的看到界面表现,上手快,所以在客户端SDK测试中比较常用,也是比较有效的。
|
||||
|
||||
但这种测试方式的缺点也很多,Demo对接口和业务场景覆盖比较有限,对接口的输入输出参数不能全覆盖,发现问题时定位复杂度增加。精心设计的Demo以及多解决方案的形式或许可以最大程度满足测试需要,但是需要较大的Demo开发测试投入,也使得问题暴露的时间大大滞后。基于Demo和解决方案的测试,可以是手工的也可以是UI层自动化测试。
|
||||
|
||||
2、基于接口调用的自动化测试
|
||||
基于接口调用的测试,包括对单个接口的测试,也包括业务场景的覆盖。这种测试方式直接有效,需要一定开发基础
|
||||
|
||||
比如 SDK Repo(功能实现代码 + XCTest Case 代码),通过脚本同步 SDK 代码到测试 Repo,主要包括:SDK 功能实现代码 + XCTest Case 代码 + QA 的 XCTest 代码(Special TestCase + Normal TestCase)
|
||||
其中,开发的测试 Case 走基础单元测试。QA 的 Special Test Case,专项测试的测试 Case(最小回归集等),日常测试的测试 Case
|
||||
|
||||
基于接口调用的自动化测试,需要有产品的思路、开发的知识和测试的思维,做起来有难度。但是因为SDK接口通常比较稳定,所以一旦实现并投入使用,测试效率和质量的收益都很大,值得拥有。
|
||||
|
||||
3、基于代码的单元测试
|
||||
单元测试是为开发代码质量保驾护航的一个重要环节,在测试左移推进的道路上,大家越来越意识到单元测试的重要价值。特别是在一些核心业务上,值得开发同学投入精力去做。
|
||||
|
||||
其他测试类型的展开,跟应用层测试类似,就不再重复了。
|
||||
|
||||
@@ -102,4 +102,4 @@
|
||||
* [96、一个提高 App 运算性能的想法](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.96.md)
|
||||
* [97、__attribute__ 的骚操作](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.97.md)
|
||||
* [98、前端、BFF、后端一些常见的设计模式](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.98.md)
|
||||
* [99、App 质量把控](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.99.md)
|
||||
* [99、客户端质量把控](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.99.md)
|
||||
@@ -847,6 +847,5 @@ app.listen(33855)
|
||||
1. App 包体积大小是一个工程治理的一个永恒话题,伴随着 App 每一次版本发布的生命周期,App 包大小的意义就不再赘述,这里讲讲【App 包体积】这个命题如何与 Electron 结合起来。
|
||||
|
||||
App 包体积的治理方案可以查看 [App瘦身之道](./../ Chapter1\ -\ iOS/1.60.md) 这篇文章。目的是通过 Electron 这个技术打造有赞自己的移动潘多拉魔盒,囊括必要的各种能力,所以【App 包体积】这个命题可以结合 Electron,将包大小检测能力作为魔盒的能力之一。
|
||||
|
||||
|
||||
|
||||
2. 桌面端技术选型的时候现在多了一些选择:Electron、[Tauri](https://github.com/tauri-apps/tauri)、ImGui。其中 Tauri 就是 WebView + Rust 的实现。ImGui 是一个 C/C++ 实现的即时渲染框架。
|
||||
@@ -101,7 +101,7 @@
|
||||
* [96、一个提高 App 运算性能的想法](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.96.md)
|
||||
* [97、__attribute__ 的骚操作](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.97.md)
|
||||
* [98、前端、BFF、后端一些常见的设计模式](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.98.md)
|
||||
* [99、App 质量把控](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.99.md)
|
||||
* [99、客户端质量把控](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.99.md)
|
||||
|
||||
* [Chapter2 - Web FrontEnd](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter2%20-%20Web%20FrontEnd/chapter2.md)
|
||||
* [1、-last-child与-last-of-type你只是会用,有研究过区别吗?](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter2%20-%20Web%20FrontEnd/2.1.md)
|
||||
|
||||
Reference in New Issue
Block a user