docs: 写好测试,提升应用质量

This commit is contained in:
杭城小刘
2020-07-15 02:56:46 +08:00
parent 6f3a608316
commit 4c6ccac464
4 changed files with 144 additions and 55 deletions

View File

@@ -248,7 +248,7 @@ TDD 强调不断的测试推动代码的开发,这样`简化了`代码,保
TDD 开发过程类似下图:
<a name="TDDStructure"></a>![](./../assets/2020-07-13-TDDStructure.png)
<a name="TDDStructure"></a>![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-13-TDDStructure.png)
- 先编写该功能的测试用例,实现测试代码。这时候去跑测试,是不通过的,也就是到了红色的状态
- 然后编写真正的功能实现代码。这时候去跑测试,测试通过,也就是到了绿色的状态
@@ -266,11 +266,11 @@ TDD 开发过程类似下图:
1. 新建一个工程,确保 “Include Unit Tests” 选项是选中的状态
![TDD Step 1](./../assets/2020-07-13-TDDStep1.png)
![TDD Step 1](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-13-TDDStep1.png)
2. 创建后的工程目录如下
![TDD step2](./../assets/2020-07-13-TDDStep2.png)
![TDD step2](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-13-TDDStep2.png)
3. 删除 Xcode 创建的测试模版文件 `TDDDemoTests.m`
@@ -284,7 +284,7 @@ TDD 开发过程类似下图:
6. 实现测试用例代码。创建继承自 Unit Test Case class 的测试类,命名为 `工程前缀+测试类名+Test`,也就是 `TDDPersonTest.m`。
![TDD step 3](./../assets/2020-07-13-TDDStep3.png)
![TDD step 3](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-13-TDDStep3.png)
7. 因为要测试 Person 类,所以在主工程中创建 Person 类
@@ -986,67 +986,158 @@ SPEC_END
很多 UI 自动化测试框架的底层实现都依赖于 `Accessibility`,也就是 App 可用性。`UI Accessibility` 是 iOS 3.0 引入的一个人性化功能,帮助身体不便的人士方便使用 App。
Accessibility 通过对 UI 元素进行分类和标记。分类成类似按钮、文本框、文本等类型,使用 identifier 来区分不同 UI 元素。[无痕埋点的设计与实现](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.55.md)里面也使用 `accessibilityIdentifier` 来绑定业务数据。
1. 使用 Xcode 自带的 UI测试则在创建工程的时候需要勾选 “Include UI Tests”。
2. 像单元测试意义UI 测试方法命名以 test 开头。将鼠标光标移到方法内,点击 Xcode 左下方的红色按钮,开始录制 UI 脚本。
![UI 脚本录制](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-15-XcodeUITesting.png)
解释说明:
```objective-c
/*! Proxy for an application that may or may not be running. */
@interface XCUIApplication : XCUIElement
// ...
@end
```
- `XCUIApplication launch` 来启动测试。`XCUIApplication` 是 UIApplication 在测试进程中的代理,用来和 App 进行一些交互。
- 使用 `staticTexts`来获取当前屏幕上的静态文本UILabel元素的代理。等价于 `[app descendantsMatchingType:XCUIElementTypeStaticText]`。XCUIElementTypeStaticText 参数是枚举类型。
```objective-c
typedef NS_ENUM(NSUInteger, XCUIElementType) {
XCUIElementTypeAny = 0,
XCUIElementTypeOther = 1,
XCUIElementTypeApplication = 2,
XCUIElementTypeGroup = 3,
XCUIElementTypeWindow = 4,
XCUIElementTypeSheet = 5,
XCUIElementTypeDrawer = 6,
XCUIElementTypeAlert = 7,
XCUIElementTypeDialog = 8,
XCUIElementTypeButton = 9,
XCUIElementTypeRadioButton = 10,
XCUIElementTypeRadioGroup = 11,
XCUIElementTypeCheckBox = 12,
XCUIElementTypeDisclosureTriangle = 13,
XCUIElementTypePopUpButton = 14,
XCUIElementTypeComboBox = 15,
XCUIElementTypeMenuButton = 16,
XCUIElementTypeToolbarButton = 17,
XCUIElementTypePopover = 18,
XCUIElementTypeKeyboard = 19,
XCUIElementTypeKey = 20,
XCUIElementTypeNavigationBar = 21,
XCUIElementTypeTabBar = 22,
XCUIElementTypeTabGroup = 23,
XCUIElementTypeToolbar = 24,
XCUIElementTypeStatusBar = 25,
XCUIElementTypeTable = 26,
XCUIElementTypeTableRow = 27,
XCUIElementTypeTableColumn = 28,
XCUIElementTypeOutline = 29,
XCUIElementTypeOutlineRow = 30,
XCUIElementTypeBrowser = 31,
XCUIElementTypeCollectionView = 32,
XCUIElementTypeSlider = 33,
XCUIElementTypePageIndicator = 34,
XCUIElementTypeProgressIndicator = 35,
XCUIElementTypeActivityIndicator = 36,
XCUIElementTypeSegmentedControl = 37,
XCUIElementTypePicker = 38,
XCUIElementTypePickerWheel = 39,
XCUIElementTypeSwitch = 40,
XCUIElementTypeToggle = 41,
XCUIElementTypeLink = 42,
XCUIElementTypeImage = 43,
XCUIElementTypeIcon = 44,
XCUIElementTypeSearchField = 45,
XCUIElementTypeScrollView = 46,
XCUIElementTypeScrollBar = 47,
XCUIElementTypeStaticText = 48,
XCUIElementTypeTextField = 49,
XCUIElementTypeSecureTextField = 50,
XCUIElementTypeDatePicker = 51,
XCUIElementTypeTextView = 52,
XCUIElementTypeMenu = 53,
XCUIElementTypeMenuItem = 54,
XCUIElementTypeMenuBar = 55,
XCUIElementTypeMenuBarItem = 56,
XCUIElementTypeMap = 57,
XCUIElementTypeWebView = 58,
XCUIElementTypeIncrementArrow = 59,
XCUIElementTypeDecrementArrow = 60,
XCUIElementTypeTimeline = 61,
XCUIElementTypeRatingIndicator = 62,
XCUIElementTypeValueIndicator = 63,
XCUIElementTypeSplitGroup = 64,
XCUIElementTypeSplitter = 65,
XCUIElementTypeRelevanceIndicator = 66,
XCUIElementTypeColorWell = 67,
XCUIElementTypeHelpTag = 68,
XCUIElementTypeMatte = 69,
XCUIElementTypeDockItem = 70,
XCUIElementTypeRuler = 71,
XCUIElementTypeRulerMarker = 72,
XCUIElementTypeGrid = 73,
XCUIElementTypeLevelIndicator = 74,
XCUIElementTypeCell = 75,
XCUIElementTypeLayoutArea = 76,
XCUIElementTypeLayoutItem = 77,
XCUIElementTypeHandle = 78,
XCUIElementTypeStepper = 79,
XCUIElementTypeTab = 80,
XCUIElementTypeTouchBar = 81,
XCUIElementTypeStatusItem = 82,
};
```
- 通过 `XCUIApplication` 实例化对象调用 `descendantsMatchingType:` 方法得到的是 `XCUIElementQuery` 类型。比如 `@property (readonly, copy*) XCUIElementQuery *staticTexts;`
```objective-c
/*! Returns a query for all descendants of the element matching the specified type. */
- (XCUIElementQuery *)descendantsMatchingType:(XCUIElementType)type;
```
- `descendantsMatchingType` 返回所有后代的类型匹配对象。`childrenMatchingType` 返回当前层级子元素的类型匹配对象
```objective-c
/*! Returns a query for direct children of the element matching the specified type. */
- (XCUIElementQuery *)childrenMatchingType:(XCUIElementType)type;
```
- 拿到 `XCUIElementQuery` 后不能直接拿到 `XCUIElement`。和 `XCUIApplication` 类似,`XCUIElement` 不能直接访问 UI 元素,它是 UI 元素在测试框架中的代理。可以通过 `Accessibility` 中的 `frame`、`identifier` 来获取。
对比很多自动化测试框架都需要找出 UI 元素,也就是借助于 `Accessibility` 的 `identifier`。这里的唯一标识生成对比[为 UIAutomation 添加自动化测试标签的探索](http://yulingtianxia.com/blog/2016/03/28/Add-UITest-Label-for-UIAutomation/)]
第三方 UI 自动化测试框架挺多的,可以查看下典型的 [appium](https://github.com/appium/appium)、[macaca](https://github.com/alibaba/macaca)。
## 七、 测试经验总结
1. 背景
2. 软件测试的概念、分类
3. 本文主要想讲的测试划分。
- 每个类具有什么属性、具有什么方法都是确定的,所以拿 Objective-C 举例子,`.h` 中会有公有的属性以及方法,`.m` 中一般是私有属性和私有方法、公有方法。类的行为设计为方法,写代码之前我们一般需要做到心中有数,一个功能需要几个类、每个类的属性和方法分别是什么,需要暴露什么属性和接口。**UML图** 不是必须要画,但是需要胸有成竹。针对一个类在测试的时候 `.m` 文件中的私有方法没有办法在 Unit Test 类中访问,一般可以将需要测试的类增加分类。在分类的 `.h` 文件中将方法进行声明。在测试的 Uint Test 中引入分类头文件。下面举例子
```Objective-C
// Person.h
- (void)eat;
// Person.m
- (void)eat
{
NSLog(@"eat");
}
- (vood)sleep
{
NSLog(@"sleep");
}
// Person+UnitTestHelper.h
- (void)sleep;
```
另一种思路是没必要针对每个类的私有方法或者每个方法进行测试,因为等全部功能做完后针对每个类的接口测试,一般会覆盖据大多数的方法。等测试完看如果方法未被覆盖,则针对性的补充 Unit Test
TDD 写好测试再写业务代码BDD 先写实现代码,再写基于行为的测试代码。另一种思路是没必要针对每个类的私有方法或者每个方法进行测试,因为等全部功能做完后针对每个类的接口测试,一般会覆盖据大多数的方法。等测试完看如果方法未被覆盖,则针对性的补充 `Unit Test`。
目前UI 测试appium 还是建议在核心逻辑且长时间没有改动的情况下去做,这样子每次发版本的时候可以当作核心逻辑回归了,目前来看价值是方便后续的迭代和维护上有一些便利性。其他的功能性测试还是走 BDD。
对于类、函数、方法的走 TDD老老实实写 UT、走 UT 覆盖率的把控
对于类、函数、方法的走 TDD老老实实写 UT、走 UT 覆盖率的把控
> 目前,UITesting 还是建议在核心逻辑且长时间没有改动的情况下去做,这样子每次发版本的时候可以当作核心逻辑回归,目前来看价值是方便后续的迭代和维护上有一些便利性。例如之前我们分享SDK升级微信和QQSDK以便支持 universal link 功能当时有了UITesing基本上免去了测试人员介入。
UITesting 还是建议在核心逻辑且长时间没有改动的情况下去做,这样子每次发版本的时候可以当作核心逻辑回归,目前来看价值是方便后续的迭代和维护上有一些便利性。例如用户中心 SDK 升级当时有了UITesing基本上免去了测试人员介入。
> 如果是一些活动页和逻辑经常变动的,老老实实走测试黑盒...
如果是一些活动页和逻辑经常变动的,老老实实走测试黑盒...
> 我觉得一直有个误区,就是觉得自动测试是为了质量,其实质量都是附送的,测试先行是让开发更快更爽的
我觉得一直有个误区,就是觉得自动测试是为了质量,其实质量都是附送的,测试先行是让开发更快更爽的
> appium 但是后来他自己也说 在iOS平台好像不是很好搞 能做的事情挺少的
![测试占比](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2020-07-14-TestingPercentage.png)
> 投入产出比是不高 那你试试monkey test
> wwdc上这张图也很清楚UI其实需要的占比很小的还是要靠单测驱动
> 当时我找个UITest的bug都花了不少力气
> UTTest主要测逻辑的
> UITest可以测你页面渲染的对不对、按钮点击是否有问题
不过 macaca appium 都可以做到iOS自动化
WWDC 这张图也很清楚UI 其实需要的占比较小,还是要靠单测驱动。

View File

@@ -1,2 +0,0 @@
# 打造一个通用、可配置、多句柄的数据上报 SDK

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB