mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-24 20:00:37 +00:00
docs: 写好测试,提升应用质量
This commit is contained in:
@@ -248,7 +248,7 @@ TDD 强调不断的测试推动代码的开发,这样`简化了`代码,保
|
||||
|
||||
TDD 开发过程类似下图:
|
||||
|
||||
<a name="TDDStructure"></a>
|
||||
<a name="TDDStructure"></a>
|
||||
|
||||
- 先编写该功能的测试用例,实现测试代码。这时候去跑测试,是不通过的,也就是到了红色的状态
|
||||
- 然后编写真正的功能实现代码。这时候去跑测试,测试通过,也就是到了绿色的状态
|
||||
@@ -266,11 +266,11 @@ TDD 开发过程类似下图:
|
||||
|
||||
1. 新建一个工程,确保 “Include Unit Tests” 选项是选中的状态
|
||||
|
||||

|
||||

|
||||
|
||||
2. 创建后的工程目录如下
|
||||
|
||||

|
||||

|
||||
|
||||
3. 删除 Xcode 创建的测试模版文件 `TDDDemoTests.m`
|
||||
|
||||
@@ -284,7 +284,7 @@ TDD 开发过程类似下图:
|
||||
|
||||
6. 实现测试用例代码。创建继承自 Unit Test Case class 的测试类,命名为 `工程前缀+测试类名+Test`,也就是 `TDDPersonTest.m`。
|
||||
|
||||

|
||||

|
||||
|
||||
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 脚本。
|
||||
|
||||

|
||||
|
||||
解释说明:
|
||||
|
||||
```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平台好像不是很好搞 能做的事情挺少的
|
||||

|
||||
|
||||
> 投入产出比是不高 那你试试monkey test
|
||||
|
||||
> wwdc上这张图也很清楚,UI其实需要的占比很小的,还是要靠单测驱动
|
||||
|
||||
> 当时我找个UITest的bug都花了不少力气
|
||||
|
||||
> UTTest主要测逻辑的
|
||||
|
||||
> UITest可以测你页面渲染的对不对、按钮点击是否有问题
|
||||
|
||||
不过 macaca appium 都可以做到iOS自动化
|
||||
WWDC 这张图也很清楚,UI 其实需要的占比较小,还是要靠单测驱动。
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# 打造一个通用、可配置、多句柄的数据上报 SDK
|
||||
|
||||
|
||||
BIN
assets/2020-07-14-TestingPercentage.png
Normal file
BIN
assets/2020-07-14-TestingPercentage.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
BIN
assets/2020-07-15-XcodeUITesting.png
Normal file
BIN
assets/2020-07-15-XcodeUITesting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 406 KiB |
Reference in New Issue
Block a user