• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 自动化测试框架使用介绍
2
3## 简介
4 OpenHarmony自动化测试框架代码部件仓arkXtest,包含单元测试框架(JsUnit)和Ui测试框架(UiTest)。
5
6 单元测试框架(JsUnit)提供单元测试用例执行能力,提供用例编写基础接口,生成对应报告,用于测试系统或应用接口。
7
8 Ui测试框架(UiTest)通过简洁易用的API提供查找和操作界面控件能力,支持用户开发基于界面操作的自动化测试脚本。
9
10## 目录
11
12```
13arkXtest
14  |-----jsunit  单元测试框架
15  |-----uitest  Ui测试框架
16```
17## 约束限制
18本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
19
20## 单元测试框架功能特性
21
22| No.  | 特性     | 功能说明                                                     |
23| ---- | -------- | ------------------------------------------------------------ |
24| 1    | 基础流程 | 支持编写及异步执行基础用例。                                 |
25| 2    | 断言库   | 判断用例实际期望值与预期值是否相符。                         |
26| 3    | Mock能力 | 支持函数级mock能力,对定义的函数进行mock后修改函数的行为,使其返回指定的值或者执行某种动作。 |
27| 4    | 数据驱动 | 提供数据驱动能力,支持复用同一个测试脚本,使用不同输入数据驱动执行。 |
28| 5    | 专项能力 | 支持测试套与用例筛选、随机执行、压力测试、超时设置、遇错即停模式,跳过,支持测试套嵌套等。 |
29
30### 使用说明
31
32####  基础流程
33
34测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。
35
36| No. | API               | 功能说明                                                                   |
37|-----| ----------------- |------------------------------------------------------------------------|
38| 1   | describe          | 定义一个测试套,支持两个参数:测试套名称和测试套函数。                                            |
39| 2   | beforeAll         | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数。                        |
40| 3   | beforeEach        | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数。          |
41| 4   | afterEach         | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数。          |
42| 5   | afterAll          | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数。                        |
43| 6   | beforeItSpecified | @since1.0.15在测试套内定义一个单元预置条件,仅在指定测试用例开始前执行,支持两个参数:单个用例名称或用例名称数组、预置动作函数。 |
44| 7   | afterItSpecified  | @since1.0.15在测试套内定义一个单元清理条件,仅在指定测试用例结束后执行,支持两个参数:单个用例名称或用例名称数组、清理动作函数  |
45| 8   | it                | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数。                                        |
46| 9   | expect            | 支持bool类型判断等多种断言方法。                                                     |
47| 10  | xdescribe    | @since1.0.17定义一个跳过的测试套,支持两个参数:测试套名称和测试套函数。                             |
48| 11  | xit                | @since1.0.17定义一条跳过的测试用例,支持三个参数:用例名称,过滤参数和用例函数。                         |
49
50
51beforeItSpecified, afterItSpecified 示例代码:
52
53```javascript
54import { describe, it, expect, beforeItSpecified, afterItSpecified } from '@ohos/hypium';
55export default function beforeItSpecifiedTest() {
56  describe('beforeItSpecifiedTest', () => {
57    beforeItSpecified(['String_assertContain_success'], () => {
58      const num:number = 1;
59      expect(num).assertEqual(1);
60    })
61    afterItSpecified(['String_assertContain_success'], async (done: Function) => {
62      const str:string = 'abc';
63      setTimeout(()=>{
64        try {
65          expect(str).assertContain('b');
66        } catch (error) {
67          console.error(`error message ${JSON.stringify(error)}`);
68        }
69        done();
70      }, 1000)
71    })
72    it('String_assertContain_success', 0, () => {
73      let a: string = 'abc';
74      let b: string = 'b';
75      expect(a).assertContain(b);
76      expect(a).assertEqual(a);
77    })
78  })
79}
80```
81
82####  断言库
83
84##### 断言功能列表
85
86
87| No.  | API                | 功能说明                                                     |
88| :--- | :------------------| ------------------------------------------------------------ |
89| 1    | assertClose        | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1)。 |
90| 2    | assertContain      | 检验actualvalue中是否包含expectvalue。                       |
91| 3    | assertEqual        | 检验actualvalue是否等于expectvalue[0]。                      |
92| 4    | assertFail         | 抛出一个错误。                                               |
93| 5    | assertFalse        | 检验actualvalue是否是false。                                 |
94| 6    | assertTrue         | 检验actualvalue是否是true。                                  |
95| 7    | assertInstanceOf   | 检验actualvalue是否是expectvalue类型,支持基础类型。                |
96| 8    | assertLarger       | 检验actualvalue是否大于expectvalue。                         |
97| 9    | assertLess         | 检验actualvalue是否小于expectvalue。                         |
98| 10   | assertNull         | 检验actualvalue是否是null。                                  |
99| 11   | assertThrowError   | 检验actualvalue抛出Error内容是否是expectValue。              |
100| 12   | assertUndefined    | 检验actualvalue是否是undefined。                             |
101| 13   | assertNaN          | @since1.0.4 检验actualvalue是否是一个NAN                     |
102| 14   | assertNegUnlimited | @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY |
103| 15   | assertPosUnlimited | @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY |
104| 16   | assertDeepEquals   | @since1.0.4 检验actualvalue和expectvalue是否完全相等   |
105| 17   | assertPromiseIsPending | @since1.0.4 判断promise是否处于Pending状态。             |
106| 18   | assertPromiseIsRejected | @since1.0.4 判断promise是否处于Rejected状态。           |
107| 19   | assertPromiseIsRejectedWith | @since1.0.4 判断promise是否处于Rejected状态,并且比较执行的结果值。 |
108| 20   | assertPromiseIsRejectedWithError | @since1.0.4 判断promise是否处于Rejected状态并有异常,同时比较异常的类型和message值。       |
109| 21   | assertPromiseIsResolved | @since1.0.4 判断promise是否处于Resolved状态。           |
110| 22   | assertPromiseIsResolvedWith | @since1.0.4 判断promise是否处于Resolved状态,并且比较执行的结果值。 |
111| 23   | not                | @since1.0.4 断言取反,支持上面所有的断言功能                     |
112| 24   | message                | @since1.0.17自定义断言异常信息 |
113
114expect断言示例代码:
115
116```javascript
117import { describe, it, expect } from '@ohos/hypium';
118
119export default function expectTest() {
120  describe('expectTest', () => {
121    it('assertBeClose_success', 0, () => {
122      let a: number = 100;
123      let b: number = 0.1;
124      expect(a).assertClose(99, b);
125    })
126    it('assertInstanceOf_success', 0, () => {
127      let a: string = 'strTest';
128      expect(a).assertInstanceOf('String');
129    })
130    it('assertNaN_success', 0, () => {
131      expect(Number.NaN).assertNaN(); // true
132    })
133    it('assertNegUnlimited_success', 0, () => {
134      expect(Number.NEGATIVE_INFINITY).assertNegUnlimited(); // true
135    })
136    it('assertPosUnlimited_success', 0, () => {
137      expect(Number.POSITIVE_INFINITY).assertPosUnlimited(); // true
138    })
139    it('not_number_true', 0, () => {
140      expect(1).not().assertLargerOrEqual(2);
141    })
142    it('not_number_true_1', 0, () => {
143      expect(3).not().assertLessOrEqual(2);
144    })
145    it('not_NaN_true', 0, () => {
146      expect(3).not().assertNaN();
147    })
148    it('not_contain_true', 0, () => {
149      let a: string = "abc";
150      let b: string = "cdf";
151      expect(a).not().assertContain(b);
152    })
153    it('not_large_true', 0, () => {
154      expect(3).not().assertLarger(4);
155    })
156    it('not_less_true', 0, () => {
157      expect(3).not().assertLess(2);
158    })
159    it('not_undefined_true', 0, () => {
160      expect(3).not().assertUndefined();
161    })
162    it('deepEquals_null_true', 0, () => {
163      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
164      expect(null).assertDeepEquals(null);
165    })
166    it('deepEquals_array_not_have_true', 0, () => {
167      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
168      const a: Array<number> = [];
169      const b: Array<number> = [];
170      expect(a).assertDeepEquals(b);
171    })
172    it('deepEquals_map_equal_length_success', 0, () => {
173      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
174      const a: Map<number, number> = new Map();
175      const b: Map<number, number> = new Map();
176      a.set(1, 100);
177      a.set(2, 200);
178      b.set(1, 100);
179      b.set(2, 200);
180      expect(a).assertDeepEquals(b);
181    })
182    it("deepEquals_obj_success_1", 0, () => {
183      const a: SampleTest = {x: 1};
184      const b: SampleTest = {x: 1};
185      expect(a).assertDeepEquals(b);
186    })
187    it("deepEquals_regExp_success_0", 0, () => {
188      const a: RegExp = new RegExp("/test/");
189      const b: RegExp = new RegExp("/test/");
190      expect(a).assertDeepEquals(b);
191    })
192    it('test_isPending_pass_1', 0, () => {
193      let p: Promise<void> = new Promise<void>(() => {});
194      expect(p).assertPromiseIsPending();
195    })
196    it('test_isRejected_pass_1', 0, () => {
197      let info: PromiseInfo = {res: "no"};
198      let p: Promise<PromiseInfo> = Promise.reject(info);
199      expect(p).assertPromiseIsRejected();
200    })
201    it('test_isRejectedWith_pass_1', 0, () => {
202      let info: PromiseInfo = {res: "reject value"};
203      let p: Promise<PromiseInfo> = Promise.reject(info);
204      expect(p).assertPromiseIsRejectedWith(info);
205    })
206    it('test_isRejectedWithError_pass_1', 0, () => {
207      let p1: Promise<TypeError> = Promise.reject(new TypeError('number'));
208      expect(p1).assertPromiseIsRejectedWithError(TypeError);
209    })
210    it('test_isResolved_pass_1', 0, () => {
211      let info: PromiseInfo = {res: "result value"};
212      let p: Promise<PromiseInfo> = Promise.resolve(info);
213      expect(p).assertPromiseIsResolved();
214    })
215    it('test_isResolvedTo_pass_1', 0, () => {
216      let info: PromiseInfo = {res: "result value"};
217      let p: Promise<PromiseInfo> = Promise.resolve(info);
218      expect(p).assertPromiseIsResolvedWith(info);
219    })
220    it("test_message", 0, () => {
221      expect(1).message('1 is not equal 2!').assertEqual(2); // fail
222    })
223  })
224}
225
226interface SampleTest {
227  x: number;
228}
229
230interface PromiseInfo {
231  res: string;
232}
233```
234
235##### 自定义断言@since1.0.18
236
237示例代码:
238
239```javascript
240import { describe, Assert, beforeAll, expect, Hypium, it } from '@ohos/hypium';
241
242// custom.ets
243interface customAssert extends Assert {
244  // 自定义断言声明
245  myAssertEqual(expectValue: boolean): void;
246}
247
248//自定义断言实现
249let myAssertEqual = (actualValue: boolean, expectValue: boolean) => {
250  interface R {
251  pass: boolean,
252  message: string
253}
254
255let result: R = {
256  pass: true,
257  message: 'just is a msg'
258}
259
260let compare = () => {
261  if (expectValue === actualValue) {
262    result.pass = true;
263    result.message = '';
264  } else {
265    result.pass = false;
266    result.message = 'expectValue !== actualValue!';
267  }
268  return result;
269}
270result = compare();
271return result;
272}
273
274export default function customAssertTest() {
275  describe('customAssertTest', () => {
276    beforeAll(() => {
277      //注册自定义断言,只有先注册才可以使用
278      Hypium.registerAssert(myAssertEqual);
279    })
280    it('assertContain1', 0, () => {
281      let a = true;
282      let b = true;
283      (expect(a) as customAssert).myAssertEqual(b);
284      Hypium.unregisterAssert(myAssertEqual);
285    })
286    it('assertContain2', 0, () => {
287      Hypium.registerAssert(myAssertEqual);
288      let a = true;
289      let b = true;
290      (expect(a) as customAssert).myAssertEqual(b);
291      // 注销自定义断言,注销以后就无法使用
292      Hypium.unregisterAssert(myAssertEqual);
293      try {
294        (expect(a) as customAssert).myAssertEqual(b);
295      }catch(e) {
296        expect(e.message).assertEqual("myAssertEqual is unregistered");
297      }
298    })
299  })
300}
301```
302
303#### Mock能力
304
305##### 约束限制
306
307单元测试框架Mock能力从npm包[1.0.1版本](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fhypium)开始支持,需修改源码工程中package.info中配置依赖npm包版本号后使用。
308> -  仅支持mock自定义对象,不支持mock系统API对象。
309> -  不支持mock对象的私有函数。
310-  **接口列表:**
311
312| No. | API | 功能说明 |
313| --- | --- | --- |
314| 1 | mockFunc(obj: object, f:function()) | mock某个类的对象obj的函数f,那么需要传两个参数:obj和f,支持使用异步函数(说明:对mock而言原函数实现是同步或异步没太多区别,因为mock并不关注原函数的实现)。 |
315| 2 | when(mockedfunc:function) | 对传入后方法做检查,检查是否被mock并标记过,返回的是一个方法声明。 |
316| 3 | afterReturn(x:value) | 设定预期返回一个自定义的值value,比如某个字符串或者一个promise。 |
317| 4 | afterReturnNothing() | 设定预期没有返回值,即 undefined。 |
318| 5 | afterAction(x:action) | 设定预期返回一个函数执行的操作。 |
319| 6 | afterThrow(x:msg) | 设定预期抛出异常,并指定异常msg。 |
320| 7 | clear() | 用例执行完毕后,进行数据mocker对象的还原处理(还原之后对象恢复被mock之前的功能)。 |
321| 8 | any | 设定用户传任何类型参数(undefined和null除外),执行的结果都是预期的值,使用ArgumentMatchers.any方式调用。 |
322| 9 | anyString | 设定用户传任何字符串参数,执行的结果都是预期的值,使用ArgumentMatchers.anyString方式调用。 |
323| 10 | anyBoolean | 设定用户传任何boolean类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyBoolean方式调用。 |
324| 11 | anyFunction | 设定用户传任何function类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyFunction方式调用。 |
325| 12 | anyNumber | 设定用户传任何数字类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyNumber方式调用。 |
326| 13 | anyObj | 设定用户传任何对象类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyObj方式调用。 |
327| 14 | matchRegexs(Regex) | 设定用户传任何正则表达式类型参数Regex,执行的结果都是预期的值,使用ArgumentMatchers.matchRegexs(Regex)方式调用。 |
328| 15 | verify(methodName, argsArray) | 验证methodName(函数名字符串)所对应的函数和其参数列表argsArray的执行行为是否符合预期,返回一个VerificationMode:一个提供验证模式的类,它有times(count)、once()、atLeast(x)、atMost(x)、never()等函数可供选择。 |
329| 16 | times(count) | 验证行为调用过count次。 |
330| 17 | once() | 验证行为调用过一次。 |
331| 18 | atLeast(count) | 验证行为至少调用过count次。 |
332| 19 | atMost(count) | 验证行为至多调用过count次。 |
333| 20 | never | 验证行为从未发生过。 |
334| 21 | ignoreMock(obj, method) | 使用ignoreMock可以还原obj对象中被mock后的函数,对被mock后的函数有效。 |
335| 22 | clearAll() | 用例执行完毕后,进行数据和内存清理。 |
336
337-  **使用示例:**
338
339用户可以通过以下方式进行引入mock模块进行测试用例编写:
340
341- **须知:**
342使用时候必须引入的mock能力模块: MockKit,when
343根据自己用例需要引入断言能力api
344例如:`import { describe, expect, it, MockKit, when} from '@ohos/hypium'`
345
346**示例1: afterReturn 的使用**
347
348```javascript
349import { describe, expect, it, MockKit, when } from '@ohos/hypium';
350
351class ClassName {
352  constructor() {
353  }
354
355  method_1(arg: string) {
356    return '888888';
357  }
358
359  method_2(arg: string) {
360    return '999999';
361  }
362}
363export default function afterReturnTest() {
364  describe('afterReturnTest', () => {
365    it('afterReturnTest', 0, () => {
366      console.info("it1 begin");
367      // 1.创建一个mock能力的对象MockKit
368      let mocker: MockKit = new MockKit();
369      // 2.定类ClassName,里面两个函数,然后创建一个对象claser
370      let claser: ClassName = new ClassName();
371      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
372      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
373      // 4.期望claser.method_1函数被mock后, 以'test'为入参时调用函数返回结果'1'
374      when(mockfunc)('test').afterReturn('1');
375      // 5.对mock后的函数进行断言,看是否符合预期
376      // 执行成功案例,参数为'test'
377      expect(claser.method_1('test')).assertEqual('1'); // 执行通过
378    })
379  })
380}
381```
382- **须知:**
383`when(mockfunc)('test').afterReturn('1');`
384这句代码中的`('test')`是mock后的函数需要传递的匹配参数,目前支持一个参数
385`afterReturn('1')`是用户需要预期返回的结果。
386有且只有在参数是`('test')`的时候,执行的结果才是用户自定义的预期结果。
387
388**示例2: afterReturnNothing 的使用**
389
390```javascript
391import { describe, expect, it, MockKit, when } from '@ohos/hypium';
392
393class ClassName {
394  constructor() {
395  }
396
397  method_1(arg: string) {
398    return '888888';
399  }
400
401  method_2(arg: string) {
402    return '999999';
403  }
404}
405export default function  afterReturnNothingTest() {
406  describe('afterReturnNothingTest', () => {
407    it('testMockfunc', 0, () => {
408      console.info("it1 begin");
409      // 1.创建一个mock能力的对象MockKit
410      let mocker: MockKit = new MockKit();
411      // 2.定类ClassName,里面两个函数,然后创建一个对象claser
412      let claser: ClassName = new ClassName();
413      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
414      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
415      // 4.期望claser.method_1函数被mock后, 以'test'为入参时调用函数返回结果undefined
416      when(mockfunc)('test').afterReturnNothing();
417      // 5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
418      // 执行成功案例,参数为'test',这时候执行原对象claser.method_1的方法,会发生变化
419      // 这时候执行的claser.method_1不会再返回'888888',而是设定的afterReturnNothing()生效// 不返回任何值;
420      expect(claser.method_1('test')).assertUndefined(); // 执行通过
421    })
422  })
423}
424```
425
426**示例3: 设定参数类型为any ,即接受任何参数(undefine和null除外)的使用**
427
428
429- **须知:**
430需要引入ArgumentMatchers类,即参数匹配器,例如:ArgumentMatchers.any
431
432```javascript
433import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium';
434
435class ClassName {
436  constructor() {
437  }
438
439  method_1(arg: string) {
440    return '888888';
441  }
442
443  method_2(arg: string) {
444    return '999999';
445  }
446}
447export default function argumentMatchersAnyTest() {
448  describe('argumentMatchersAnyTest', () => {
449    it('testMockfunc', 0, () => {
450      console.info("it1 begin");
451      // 1.创建一个mock能力的对象MockKit
452      let mocker: MockKit = new MockKit();
453      // 2.定类ClassName,里面两个函数,然后创建一个对象claser
454      let claser: ClassName = new ClassName();
455      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
456      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
457      // 4.期望claser.method_1函数被mock后, 以任何参数调用函数时返回结果'1'
458      when(mockfunc)(ArgumentMatchers.any).afterReturn('1');
459      // 5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
460      // 执行成功的案例1,传参为字符串类型
461      expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。
462      // 执行成功的案例2,传参为数字类型123
463      expect(claser.method_1("123")).assertEqual('1');// 用例执行通过。
464      // 执行成功的案例3,传参为boolean类型true
465      expect(claser.method_1("true")).assertEqual('1');// 用例执行通过。
466    })
467  })
468}
469```
470
471**示例4: 设定参数类型ArgumentMatchers的使用**
472
473```javascript
474import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium';
475
476class ClassName {
477  constructor() {
478  }
479
480  method_1(arg: string) {
481    return '888888';
482  }
483
484  method_2(arg: string) {
485    return '999999';
486  }
487}
488export default function argumentMatchersTest() {
489  describe('argumentMatchersTest', () => {
490    it('testMockfunc', 0, () => {
491      console.info("it1 begin");
492      // 1.创建一个mock能力的对象MockKit
493      let mocker: MockKit = new MockKit();
494      // 2.定类ClassName,里面两个函数,然后创建一个对象claser
495      let claser: ClassName = new ClassName();
496      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
497      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
498      // 4.期望claser.method_1函数被mock后, 以任何string类型为参数调用函数时返回结果'1'
499      when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1');
500      // 4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
501      // 执行成功的案例,传参为字符串类型
502      expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。
503      expect(claser.method_1('abc')).assertEqual('1'); // 用例执行通过。
504    })
505  })
506}
507```
508
509**示例5: 设定参数类型为matchRegexs(Regex)等 的使用**
510```javascript
511import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium';
512
513class ClassName {
514  constructor() {
515  }
516
517  method_1(arg: string) {
518    return '888888';
519  }
520
521  method_2(arg: string) {
522    return '999999';
523  }
524}
525export default function matchRegexsTest() {
526  describe('matchRegexsTest', () => {
527    it('testMockfunc', 0, () => {
528      console.info("it1 begin");
529      // 1.创建一个mock能力的对象MockKit
530      let mocker: MockKit = new MockKit();
531      let claser: ClassName = new ClassName();
532      // 2.进行mock操作,比如需要对ClassName类的method_1函数进行mock
533      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
534      // 3.期望claser.method_1函数被mock后, 以"test"为入参调用函数时返回结果'1'
535      when(mockfunc)(ArgumentMatchers.matchRegexs(new RegExp("test"))).afterReturn('1');
536      // 4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
537      // 执行成功的案例,传参为字符串类型
538      expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。
539    })
540  })
541}
542```
543
544**示例6: 验证功能 Verify函数的使用**
545```javascript
546import { describe, it, MockKit } from '@ohos/hypium';
547
548class ClassName {
549  constructor() {
550  }
551
552  method_1(...arg: string[]) {
553    return '888888';
554  }
555
556  method_2(...arg: string[]) {
557    return '999999';
558  }
559}
560export default function verifyTest() {
561  describe('verifyTest', () => {
562    it('testMockfunc', 0, () => {
563      console.info("it1 begin");
564      // 1.创建一个mock能力的对象MockKit
565      let mocker: MockKit = new MockKit();
566      // 2.然后创建一个对象claser
567      let claser: ClassName = new ClassName();
568      // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
569      mocker.mockFunc(claser, claser.method_1);
570      mocker.mockFunc(claser, claser.method_2);
571      // 4.方法调用如下
572      claser.method_1('abc', 'ppp');
573      claser.method_1('abc');
574      claser.method_1('xyz');
575      claser.method_1();
576      claser.method_1('abc', 'xxx', 'yyy');
577      claser.method_1();
578      claser.method_2('111');
579      claser.method_2('111', '222');
580      // 5.现在对mock后的两个函数进行验证,验证method_2,参数为'111'执行过一次
581      mocker.verify('method_2',['111']).once(); // 执行success
582    })
583  })
584}
585```
586
587**示例7: ignoreMock(obj, method) 忽略函数的使用**
588```javascript
589import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium';
590
591class ClassName {
592  constructor() {
593  }
594
595  method_1(...arg: number[]) {
596    return '888888';
597  }
598
599  method_2(...arg: number[]) {
600    return '999999';
601  }
602}
603export default function ignoreMockTest() {
604  describe('ignoreMockTest', () => {
605    it('testMockfunc', 0, () => {
606      console.info("it1 begin");
607      // 1.创建一个mock能力的对象MockKit
608      let mocker: MockKit = new MockKit();
609      // 2.创建一个对象claser
610      let claser: ClassName = new ClassName();
611      // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
612      let func_1: Function = mocker.mockFunc(claser, claser.method_1);
613      let func_2: Function = mocker.mockFunc(claser, claser.method_2);
614      // 4.期望claser.method_1函数被mock后, 以number类型为入参时调用函数返回结果'4'
615      when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4');
616      // 4.期望claser.method_2函数被mock后, 以number类型为入参时调用函数返回结果'5'
617      when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5');
618      // 5.方法调用如下
619      expect(claser.method_1(123)).assertEqual("4");
620      expect(claser.method_2(456)).assertEqual("5");
621      // 6.现在对mock后的两个函数的其中一个函数method_1进行忽略处理(原理是就是还原)
622      mocker.ignoreMock(claser, claser.method_1);
623      // 7.然后再去调用 claser.method_1函数,用断言测试結果
624      expect(claser.method_1(123)).assertEqual('888888');
625    })
626  })
627}
628```
629
630**示例8: clear(obj)函数的使用**
631
632```javascript
633import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium';
634
635class ClassName {
636  constructor() {
637  }
638
639  method_1(...arg: number[]) {
640    return '888888';
641  }
642
643  method_2(...arg: number[]) {
644    return '999999';
645  }
646}
647export default function clearTest() {
648  describe('clearTest', () => {
649    it('testMockfunc', 0, () => {
650      console.info("it1 begin");
651      // 1.创建一个mock能力的对象MockKit
652      let mocker: MockKit = new MockKit();
653      // 2.创建一个对象claser
654      let claser: ClassName = new ClassName();
655      // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
656      let func_1: Function = mocker.mockFunc(claser, claser.method_1);
657      let func_2: Function = mocker.mockFunc(claser, claser.method_2);
658      // 4.期望claser.method_1函数被mock后, 以任何number类型为参数调用函数时返回结果'4'
659      when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4');
660      // 4.期望claser.method_2函数被mock后, 以任何number类型为参数调用函数时返回结果'5'
661      when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5');
662      // 5.方法调用如下
663      expect(claser.method_1(123)).assertEqual('4');
664      expect(claser.method_2(123)).assertEqual('5');
665      // 6.清除obj上所有的mock能力(原理是就是还原)
666      mocker.clear(claser);
667      // 7.然后再去调用 claser.method_1,claser.method_2 函数,测试结果
668      expect(claser.method_1(123)).assertEqual('888888');
669      expect(claser.method_2(123)).assertEqual('999999');
670    })
671  })
672}
673```
674
675**示例9: afterThrow(msg)函数的使用**
676
677```javascript
678import { describe, expect, it, MockKit, when } from '@ohos/hypium';
679
680class ClassName {
681  constructor() {
682  }
683
684  method_1(arg: string) {
685    return '888888';
686  }
687}
688export default function afterThrowTest() {
689  describe('afterThrowTest', () => {
690    it('testMockfunc', 0, () => {
691      console.info("it1 begin");
692      // 1.创建一个mock能力的对象MockKit
693      let mocker: MockKit = new MockKit();
694      // 2.创建一个对象claser
695      let claser: ClassName = new ClassName();
696      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
697      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
698      // 4.期望claser.method_1函数被mock后, 以'test'为参数调用函数时抛出error xxx异常
699      when(mockfunc)('test').afterThrow('error xxx');
700      // 5.执行mock后的函数,捕捉异常并使用assertEqual对比msg否符合预期
701      try {
702        claser.method_1('test');
703      } catch (e) {
704        expect(e).assertEqual('error xxx'); // 执行通过
705      }
706    })
707  })
708}
709```
710
711**示例10: mock异步返回promise对象的使用**
712
713```javascript
714import { describe, expect, it, MockKit, when } from '@ohos/hypium';
715
716class ClassName {
717  constructor() {
718  }
719
720  async method_1(arg: string) {
721    return new Promise<string>((resolve: Function, reject: Function) => {
722      setTimeout(() => {
723        console.log('执行');
724        resolve('数据传递');
725      }, 2000);
726    });
727  }
728}
729export default function mockPromiseTest() {
730  describe('mockPromiseTest', () => {
731    it('testMockfunc', 0, async (done: Function) => {
732      console.info("it1 begin");
733      // 1.创建一个mock能力的对象MockKit
734      let mocker: MockKit = new MockKit();
735      // 2.创建一个对象claser
736      let claser: ClassName = new ClassName();
737      // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
738      let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
739      // 4.期望claser.method_1函数被mock后, 以'test'为参数调用函数时返回一个promise对象
740      when(mockfunc)('test').afterReturn(new Promise<string>((resolve: Function, reject: Function) => {
741        console.log("do something");
742        resolve('success something');
743      }));
744      // 5.执行mock后的函数,即对定义的promise进行后续执行
745      let result = await claser.method_1('test');
746      expect(result).assertEqual("success something");
747      done();
748    })
749  })
750}
751```
752
753**示例11:verify times函数的使用(验证函数调用次数)**
754
755```javascript
756import { describe, it, MockKit, when } from '@ohos/hypium'
757
758class ClassName {
759  constructor() {
760  }
761
762  method_1(...arg: string[]) {
763    return '888888';
764  }
765}
766export default function verifyTimesTest() {
767  describe('verifyTimesTest', () => {
768    it('test_verify_times', 0, () => {
769      // 1.创建MockKit对象
770      let mocker: MockKit = new MockKit();
771      // 2.创建类对象
772      let claser: ClassName = new ClassName();
773      // 3.mock 类ClassName对象的某个方法,比如method_1
774      let func_1: Function = mocker.mockFunc(claser, claser.method_1);
775      // 4.期望被mock后的函数返回结果'4'
776      when(func_1)('123').afterReturn('4');
777      // 5.随机执行几次函数,参数如下
778      claser.method_1('123', 'ppp');
779      claser.method_1('abc');
780      claser.method_1('xyz');
781      claser.method_1();
782      claser.method_1('abc', 'xxx', 'yyy');
783      claser.method_1('abc');
784      claser.method_1();
785      // 6.验证函数method_1且参数为'abc'时,执行过的次数是否为2
786      mocker.verify('method_1', ['abc']).times(2);
787    })
788  })
789}
790```
791
792
793**示例12:verify atLeast函数的使用(验证函数调用次数)**
794
795```javascript
796import { describe, it, MockKit, when } from '@ohos/hypium'
797
798class ClassName {
799  constructor() {
800  }
801
802  method_1(...arg: string[]) {
803    return '888888';
804  }
805}
806export default function verifyAtLeastTest() {
807  describe('verifyAtLeastTest', () => {
808    it('test_verify_atLeast', 0, () => {
809      // 1.创建MockKit对象
810      let mocker: MockKit = new MockKit();
811      // 2.创建类对象
812      let claser: ClassName = new ClassName();
813      // 3.mock  类ClassName对象的某个方法,比如method_1
814      let func_1: Function = mocker.mockFunc(claser, claser.method_1);
815      // 4.期望被mock后的函数返回结果'4'
816      when(func_1)('123').afterReturn('4');
817      // 5.随机执行几次函数,参数如下
818      claser.method_1('123', 'ppp');
819      claser.method_1('abc');
820      claser.method_1('xyz');
821      claser.method_1();
822      claser.method_1('abc', 'xxx', 'yyy');
823      claser.method_1();
824      // 6.验证函数method_1且参数为空时,是否至少执行过2次
825      mocker.verify('method_1', []).atLeast(2);
826    })
827  })
828}
829```
830
831#### 数据驱动
832
833##### 约束限制
834
835单元测试框架数据驱动能力从[框架 1.0.2版本](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fhypium)开始支持。
836
837- 数据参数传递 : 为指定测试套、测试用例传递测试输入数据参数。
838- 压力测试 : 为指定测试套、测试用例设置执行次数。
839
840数据驱动可以根据配置参数来驱动测试用例的执行次数和每一次传入的参数,使用时依赖data.json配置文件,文件内容如下:
841
842>说明 : data.json与测试用例*.test.js|ets文件同目录
843
844```json
845{
846	"suites": [{
847		"describe": ["actsAbilityTest"],
848		"stress": 2,
849		"params": {
850			"suiteParams1": "suiteParams001",
851			"suiteParams2": "suiteParams002"
852		},
853		"items": [{
854			"it": "testDataDriverAsync",
855			"stress": 2,
856			"params": [{
857				"name": "tom",
858				"value": 5
859			}, {
860				"name": "jerry",
861				"value": 4
862			}]
863		}, {
864			"it": "testDataDriver",
865			"stress": 3
866		}]
867	}]
868}
869```
870
871配置参数说明:
872
873|      | 配置项名称 | 功能                                  | 必填 |
874| :--- | :--------- | :------------------------------------ | ---- |
875| 1    | "suite"    | 测试套配置 。                         | 是   |
876| 2    | "items"    | 测试用例配置 。                       | 是   |
877| 3    | "describe" | 测试套名称 。                         | 是   |
878| 4    | "it"       | 测试用例名称 。                       | 是   |
879| 5    | "params"   | 测试套 / 测试用例 可传入使用的参数 。 | 否   |
880| 6    | "stress"   | 测试套 / 测试用例 指定执行次数 。     | 否   |
881
882示例代码:
883
884DevEco Studio从V3.0 Release(2022-09-06)版本开始支持
885
886stage模型:
887
888在TestAbility目录下TestAbility.ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据
889
890FA模型:
891
892在TestAbility目录下app.jsapp.ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据
893
894```javascript
895import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
896import { Hypium } from '@ohos/hypium'
897import testsuite from '../test/List.test'
898import data from '../test/data.json';
899
900...
901Hypium.setData(data);
902Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
903...
904```
905
906```javascript
907 import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
908
909 export default function abilityTest() {
910  describe('actsAbilityTest', () => {
911    it('testDataDriverAsync', 0, async (done: Function, data: ParmObj) => {
912      console.info('name: ' + data.name);
913      console.info('value: ' + data.value);
914      done();
915    });
916
917    it('testDataDriver', 0, () => {
918      console.info('stress test');
919    })
920  })
921}
922 interface ParmObj {
923   name: string,
924   value: string
925 }
926```
927#### 专项能力
928
929该项能力需通过在cmd窗口中输入aa test命令执行触发,并通过设置执行参数触发不同功能。另外,测试应用模型与编译方式不同,对应的aa test命令也不同,具体可参考[自动化测试框架使用指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/application-test/arkxtest-guidelines.md#cmd%E6%89%A7%E8%A1%8C)
930
931- **筛选能力**
932
933  1、按测试用例属性筛选
934
935  可以利用框架提供的Level、Size、TestType 对象,对测试用例进行标记,以区分测试用例的级别、粒度、测试类型,各字段含义及代码如下:
936
937  | Key      | 含义说明     | Value取值范围                                                |
938  | -------- | ------------ | ------------------------------------------------------------ |
939  | level    | 用例级别     | "0","1","2","3","4", 例如:-s level 1                        |
940  | size     | 用例粒度     | "small","medium","large", 例如:-s size small                |
941  | testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function |
942
943  示例代码:
944
945 ```javascript
946 import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
947
948 export default function attributeTest() {
949  describe('attributeTest', () => {
950    it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
951      console.info('Hello Test');
952    })
953  })
954}
955 ```
956
957  示例命令:
958
959  ```shell
960  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s testType function -s size small -s level 0
961  ```
962
963  该命令作用是筛选测试应用中同时满足,用例测试类型是“function”、用例粒度是“small”、用例级别是“0”的三个条件用例执行。
964
965  2、按测试套/测试用例名称筛选
966
967  注意:测试套和测试用例的命名要符合框架规则,即以字母开头,后跟一个或多个字母、数字,不能包含特殊符号。
968
969  框架可以通过指定测试套与测试用例名称,来指定特定用例的执行,测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔
970
971  | Key      | 含义说明                | Value取值范围                                                |
972  | -------- | ----------------------- | ------------------------------------------------------------ |
973  | class    | 指定要执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt |
974  | notClass | 指定不执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttribut |
975
976  示例代码:
977
978  ```javascript
979  import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
980
981  export default function attributeTest() {
982  describe('describeTest_000',  () => {
983    it("testIt_00", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0,  () => {
984      console.info('Hello Test');
985    })
986
987    it("testIt_01", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
988      console.info('Hello Test');
989    })
990  })
991
992  describe('describeTest_001',  () => {
993    it("testIt_02", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
994      console.info('Hello Test');
995    })
996  })
997}
998  ```
999
1000  示例命令1:
1001
1002  ```shell
1003  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s class describeTest_000#testIt_00,describeTest_001
1004  ```
1005
1006  该命令作用是执行“describeTest_001”测试套中所用用例,以及“describeTest_000”测试套中的“testIt_00”用例。
1007
1008  示例命令2:
1009
1010  ```shell
1011  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s notClass describeTest_000#testIt_01
1012  ```
1013
1014  该命令作用是不执行“describeTest_000”测试套中的“testIt_01”用例。
1015
1016- **随机执行**
1017
1018  使测试套与测试用例随机执行,用于稳定性测试。
1019
1020  | Key    | 含义说明                             | Value取值范围                                  |
1021  | ------ | ------------------------------------ | ---------------------------------------------- |
1022  | random | @since1.0.3 测试套、测试用例随机执行 | true, 不传参默认为false, 例如:-s random true |
1023
1024  示例命令:
1025
1026  ```shell
1027  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s random true
1028  ```
1029
1030- **压力测试**
1031
1032  指定要执行用例的执行次数,用于压力测试。
1033
1034  | Key    | 含义说明                             | Value取值范围                  |
1035  | ------ | ------------------------------------ | ------------------------------ |
1036  | stress | @since1.0.5 指定要执行用例的执行次数 | 正整数, 例如: -s stress 1000 |
1037
1038  示例命令:
1039
1040  ```shell
1041  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s stress 1000
1042  ```
1043
1044- **用例超时时间设置**
1045
1046  指定测试用例执行的超时时间,用例实际耗时如果大于超时时间,用例会抛出"timeout"异常,用例结果会显示“excute timeout XXX”
1047
1048  | Key     | 含义说明                   | Value取值范围                                        |
1049  | ------- | -------------------------- | ---------------------------------------------------- |
1050  | timeout | 指定测试用例执行的超时时间 | 正整数(单位ms),默认为 5000,例如: -s timeout 15000 |
1051
1052  示例命令:
1053
1054  ```shell
1055  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s timeout 15000
1056  ```
1057
1058- **遇错即停模式**
1059
1060  | Key          | 含义说明                                                     | Value取值范围                                        |
1061  | ------------ | ------------------------------------------------------------ | ---------------------------------------------------- |
1062  | breakOnError | @since1.0.6 遇错即停模式,当执行用例断言失败或者发生错误时,退出测试执行流程 | true, 不传参默认为false, 例如:-s breakOnError true |
1063
1064  示例命令:
1065
1066  ```shell
1067  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s breakOnError true
1068  ```
1069
1070- **测试套中用例信息输出**
1071
1072  输出测试应用中待执行的测试用例信息
1073
1074  | Key    | 含义说明                     | Value取值范围                                  |
1075  | ------ | ---------------------------- | ---------------------------------------------- |
1076  | dryRun | 显示待执行的测试用例信息全集 | true, 不传参默认为false, 例如:-s dryRun true |
1077
1078  示例命令:
1079
1080  ```shell
1081  hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s dryRun true
1082  ```
1083
1084- **嵌套能力**
1085
1086  1.示例代码
1087  ```javascript
1088  // Test1.test.ets
1089  import { describe, expect, it } from '@ohos/hypium';
1090  import test2 from './Test2.test';
1091
1092  export default function test1() {
1093    describe('test1', () => {
1094      it('assertContain1', 0, () => {
1095        let a = true;
1096        let b = true;
1097        expect(a).assertEqual(b);
1098      })
1099      // 引入测试套test2
1100      test2();
1101    })
1102  }
1103  ```
1104
1105  ```javascript
1106  //Test2.test.ets
1107  import { describe, expect, it } from '@ohos/hypium';
1108
1109  export default function test2() {
1110    describe('test2', () => {
1111      it('assertContain1', 0, () => {
1112        let a = true;
1113        let b = true;
1114        expect(a).assertEqual(b);
1115      })
1116      it('assertContain2', 0, () => {
1117        let a = true;
1118        let b = true;
1119        expect(a).assertEqual(b);
1120      })
1121    })
1122  }
1123  ```
1124
1125  ```javascript
1126  //List.test.ets
1127  import test1 from './nest/Test1.test';
1128
1129  export default function testsuite() {
1130    test1();
1131  }
1132  ```
1133
1134  2.示例筛选参数
1135    ```shell
1136    #执行test1的全部测试用例
1137    -s class test1
1138    ```
1139    ```shell
1140    #执行test1的子测试用例
1141    -s class test1#assertContain1
1142    ```
1143    ```shell
1144    #执行test1的子测试套test2的测试用例
1145    -s class test1.test2#assertContain1
1146    ```
1147
1148- **跳过能力**
1149
1150    | Key          | 含义说明                                                     | Value取值范围                                        |
1151  | ------------ | ------------------------------------------------------------ | ---------------------------------------------------- |
1152  | skipMessage | @since1.0.17 显示待执行的测试用例信息全集中是否包含跳过测试套和跳过用例的信息 | true/false, 不传参默认为false, 例如:-s skipMessage true |
1153  | runSkipped | @since1.0.17 指定要执行的跳过测试套&跳过用例 | all,skipped,${describeName}#${itName},${describeName},不传参默认为空,例如:-s runSkipped all |
1154
1155  1.示例代码
1156
1157  ```javascript
1158  //Skip1.test.ets
1159  import { expect, xdescribe, xit } from '@ohos/hypium';
1160
1161  export default function skip1() {
1162    xdescribe('skip1', () => {
1163      //注意:在xdescribe中不支持编写it用例
1164      xit('assertContain1', 0, () => {
1165        let a = true;
1166        let b = true;
1167        expect(a).assertEqual(b);
1168      })
1169    })
1170  }
1171  ```
1172
1173    ```javascript
1174  //Skip2.test.ets
1175  import { describe, expect, xit, it } from '@ohos/hypium';
1176
1177  export default function skip2() {
1178    describe('skip2', () => {
1179      //默认会跳过assertContain1
1180      xit('assertContain1', 0, () => {
1181        let a = true;
1182        let b = true;
1183        expect(a).assertEqual(b);
1184      })
1185      it('assertContain2', 0, () => {
1186        let a = true;
1187        let b = true;
1188        expect(a).assertEqual(b);
1189      })
1190    })
1191  }
1192    ```
1193
1194
1195
1196### 使用方式
1197
1198单元测试框架以ohpm包形式发布至[服务组件官网](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fhypium),开发者可以下载Deveco Studio后,在应用工程中配置依赖后使用框架能力,测试工程创建及测试脚本执行使用指南请参见[IDE指导文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001263160453)1199
1200## Ui测试框架功能特性
1201
1202| No.  | 特性        | 功能说明                                            |
1203| ---- |-----------|-------------------------------------------------|
1204| 1    | Driver    | Ui测试的入口,提供查找控件,检查控件存在性以及注入按键能力。                 |
1205| 2    | On        | 用于描述目标控件特征(文本、id、类型等),`Driver`根据`On`描述的控件特征信息来查找控件。 |
1206| 3    | Component | Driver查找返回的控件对象,提供查询控件属性,滑动查找等触控和检视能力。          |
1207| 4    | UiWindow  | Driver查找返回的窗口对象,提供获取窗口属性、操作窗口的能力。               |
1208
1209**使用者在测试脚本通过如下方式引入使用:**
1210
1211```typescript
1212import {Driver,ON,Component,UiWindow,MatchPattern} from '@ohos.UiTest'
1213```
1214
1215> 须知
1216> 1. `On`类提供的接口全部是同步接口,使用者可以使用`builder`模式链式调用其接口构造控件筛选条件。
1217> 2. `Driver`和`Component`类提供的接口全部是异步接口(`Promise`形式),**需使用`await`语法**。
1218> 3. Ui测试用例均需使用**异步**语法编写用例,需遵循单元测试框架异步用例编写规范。
1219
1220
1221
1222在测试用例文件中import `On/Driver/Component`类,然后调用API接口编写测试用例。
1223
1224```javascript
1225import { Driver, ON, Component } from '@kit.TestKit'
1226import { describe, it, expect } from '@ohos/hypium'
1227
1228export default function findComponentTest() {
1229  describe('findComponentTest', () => {
1230    it('uitest_demo0', 0, async () => {
1231      // create Driver
1232      let driver: Driver = Driver.create();
1233      // find component by text
1234      let button: Component = await driver.findComponent(ON.text('Hello World').enabled(true));
1235      // click component
1236      await button.click();
1237      // get and assert component text
1238      let content: string = await button.getText();
1239      expect(content).assertEqual('Hello World');
1240    })
1241  })
1242}
1243```
1244
1245### Driver使用说明
1246
1247`Driver`类作为UiTest测试框架的总入口,提供查找控件,注入按键,单击坐标,滑动控件,手势操作,截图等能力。
1248
1249| No.  | API                                                             | 功能描述               |
1250| ---- |-----------------------------------------------------------------| ---------------------- |
1251| 1    | create():Promise<Driver>                                        | 静态方法,构造Driver。 |
1252| 2    | findComponent(on:On):Promise<Component>                         | 查找匹配控件。         |
1253| 3    | pressBack():Promise<void>                                       | 单击BACK键。           |
1254| 4    | click(x:number, y:number):Promise<void>                         | 基于坐标点的单击。      |
1255| 5    | swipe(x1:number, y1:number, x2:number, y2:number):Promise<void> | 基于坐标点的滑动。      |
1256| 6    | assertComponentExist(on:On):Promise<void>                       | 断言匹配的控件存在。     |
1257| 7    | delayMs(t:number):Promise<void>                                 | 延时。                 |
1258| 8    | screenCap(s:path):Promise<void>                                 | 截屏。                 |
1259| 9    | findWindow(filter: WindowFilter): Promise<UiWindow>             | 查找匹配窗口。         |
1260
1261其中assertComponentExist接口是断言API,用于断言当前界面存在目标控件;如果控件不存在,该API将抛出JS异常,使当前测试用例失败。
1262
1263```javascript
1264import { describe, it} from '@ohos/hypium';
1265import { Driver, ON } from '@kit.TestKit';
1266
1267export default function assertComponentExistTest() {
1268  describe('assertComponentExistTest', () => {
1269    it('Uitest_demo0', 0, async (done: Function) => {
1270      try{
1271        // create Driver
1272        let driver: Driver = Driver.create();
1273        // assert text 'hello' exists on current Ui
1274        await driver.assertComponentExist(ON.text('hello'));
1275      } finally {
1276        done();
1277      }
1278    })
1279  })
1280}
1281```
1282
1283`Driver`完整的API列表请参考[API文档](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts)及[示例文档说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-test-kit/js-apis-uitest.md#driver9)1284
1285### On使用说明
1286
1287Ui测试框架通过`On`类提供了丰富的控件特征描述API,用来匹配查找要操作或检视的目标控件。`On`提供的API能力具有以下特点:
1288
1289- 支持匹配单属性和匹配多属性组合,例如同时指定目标控件text和id。
1290- 控件属性支持多种匹配模式(等于,包含,`STARTS_WITH`,`ENDS_WITH`)。
1291- 支持相对定位控件,可通过`isBefore`和`isAfter`等API限定邻近控件特征进行辅助定位。
1292
1293| No. | API                                | 功能描述                       |
1294|-----|------------------------------------|----------------------------|
1295| 1   | id(i:string):On                    | 指定控件id。                    |
1296| 2   | text(t:string, p?:MatchPattern):On | 指定控件文本,可指定匹配模式。            |
1297| 3   | type(t:string):On                 | 指定控件类型。                    |
1298| 4   | enabled(e:bool):On                 | 指定控件使能状态。                  |
1299| 5   | clickable(c:bool):On               | 指定控件可单击状态。                 |
1300| 6   | longClickable(l:bool):On           | 指定控件可长按状态。                 |
1301| 7   | focused(f:bool):On                 | 指定控件获焦状态。                  |
1302| 8   | scrollable(s:bool):On              | 指定控件可滑动状态。                 |
1303| 9   | selected(s:bool):On                | 指定控件选中状态。                  |
1304| 10  | checked(c:bool):On                 | 指定控件选择状态。                  |
1305| 11  | checkable(c:bool):On               | 指定控件可选择状态。                 |
1306| 12  | isBefore(b:On):On                  | **相对定位**,限定目标控件位于指定特征控件之前。 |
1307| 13  | isAfter(b:On):On                   | **相对定位**,限定目标控件位于指定特征控件之后。 |
1308
1309其中,`text`属性支持{`MatchPattern.EQUALS`,`MatchPattern.CONTAINS`,`MatchPattern.STARTS_WITH`,`MatchPattern.ENDS_WITH`}四种匹配模式,缺省使用`MatchPattern.EQUALS`模式。
1310
1311`On`完整的API列表请参考[API文档](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts)及[示例文档说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-test-kit/js-apis-uitest.md#on9)1312
1313#### 控件绝对定位
1314
1315**示例代码1**:查找id是`Id_button`的控件。
1316
1317```javascript
1318let button: Component = await driver.findComponent(ON.id('Id_button'))
1319```
1320
1321 **示例代码2**:查找id是`Id_button`并且状态是`enabled`的控件,适用于无法通过单一属性定位的场景。
1322
1323```javascript
1324let button: Component = await driver.findComponent(ON.id('Id_button').enabled(true))
1325```
1326
1327通过`On.id(x).enabled(y)`来指定目标控件的多个属性。
1328
1329**示例代码3**:查找文本中包含`hello`的控件,适用于不能完全确定控件属性取值的场景。
1330
1331```javascript
1332let txt: Component = await driver.findComponent(ON.text('hello', MatchPattern.CONTAINS))
1333```
1334
1335通过向`On.text()`方法传入第二个参数`MatchPattern.CONTAINS`来指定文本匹配规则;默认规则是`MatchPattern.EQUALS`,即目标控件text属性必须严格等于给定值。
1336
1337####  控件相对定位
1338
1339**示例代码1**:查找位于文本控件`Item3_3`后面的,id是`Id_switch`的Switch控件。
1340
1341```javascript
1342let switch: Component = await driver.findComponent(ON.id('Id_switch').isAfter(ON.text('Item3_3')))
1343```
1344
1345通过`On.isAfter`方法,指定位于目标控件前面的特征控件属性,通过该特征控件进行相对定位。一般地,特征控件是某个具有全局唯一特征的控件(例如具有唯一的id或者唯一的text)。
1346
1347类似的,可以使用`On.isBefore`控件指定位于目标控件后面的特征控件属性,实现相对定位。
1348
1349### Component使用说明
1350
1351`Component`类代表了Ui界面上的一个控件,一般是通过`Driver.findComponent(on)`方法查找到的。通过该类的实例,用户可以获取控件属性,单击控件,滑动查找,注入文本等操作。
1352
1353`Component`包含的常用API:
1354
1355| No. | API                                | 功能描述                       |
1356|-----|------------------------------------|----------------------------|
1357| 1   | click():Promise<void>              | 单击该控件。                     |
1358| 2   | inputText(t:string):Promise<void>  | 向控件中输入文本(适用于文本框控件)。        |
1359| 3   | scrollSearch(s:On):Promise<Component>   | 在该控件上滑动查找目标控件(适用于List等控件)。 |
1360| 4   | scrollToTop(s:number):Promise<void>    | 滑动到该控件顶部(适用于List等控件)。      |
1361| 5   | scrollTobottom(s:number):Promise<void> | 滑动到该控件底部(适用于List等控件)。      |
1362| 6   | getText():Promise<string>          | 获取控件text。                  |
1363| 7   | getId():Promise<number>            | 获取控件id。                    |
1364| 8   | getType():Promise<string>          | 获取控件类型。                    |
1365| 9   | isEnabled():Promise<bool>          | 获取控件使能状态。                  |
1366
1367`Component`完整的API列表请参考[API文档](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts)及[示例文档说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-test-kit/js-apis-uitest.md#component9)1368
1369**示例代码1**:单击控件。
1370
1371```javascript
1372let button: Component = await driver.findComponent(ON.id('Id_button'))
1373await button.click()
1374```
1375
1376**示例代码2**:通过get接口获取控件属性后,可以使用单元测试框架提供的assert*接口做断言检查。
1377
1378```javascript
1379let component: Component = await driver.findComponent(ON.id('Id_title'))
1380expect(component !== null).assertTrue()
1381```
1382
1383**示例代码3**:在List控件中滑动查找text是`Item3_3`的子控件。
1384
1385```javascript
1386let list: Component = await driver.findComponent(ON.id('Id_list'))
1387let found: Component = await list.scrollSearch(ON.text('Item3_3'))
1388expect(found).assertTrue()
1389```
1390
1391**示例代码4**:向输入框控件中输入文本。
1392
1393```javascript
1394let editText: Component = await driver.findComponent(ON.type('InputText'))
1395await editText.inputText('user_name')
1396```
1397### UiWindow使用说明
1398
1399`UiWindow`类代表了Ui界面上的一个窗口,一般是通过`Driver.findWindow(WindowFilter)`方法查找到的。通过该类的实例,用户可以获取窗口属性,并进行窗口拖动、调整窗口大小等操作。
1400
1401`UiWindow`包含的常用API:
1402
1403| No.  | API                                                          | 功能描述                                           |
1404| ---- | ------------------------------------------------------------ | -------------------------------------------------- |
1405| 1    | getBundleName(): Promise<string>                             | 获取窗口所属应用包名。                             |
1406| 2    | getTitle(): Promise<string>                                  | 获取窗口标题信息。                                 |
1407| 3    | focus(): Promise<bool>                                       | 使得当前窗口获取焦点。                             |
1408| 4    | moveTo(x: number, y: number): Promise<bool>                  | 将当前窗口移动到指定位置(适用于支持移动的窗口)。 |
1409| 5    | resize(wide: number, height: number, direction: ResizeDirection): Promise<bool> | 调整窗口大小(适用于支持调整大小的窗口)。         |
1410| 6    | split(): Promise<bool>                                       | 将窗口模式切换为分屏模式(适用于支持分屏的窗口)。   |
1411| 7    | close(): Promise<bool>                                       | 关闭当前窗口。                                     |
1412
1413`UiWindow`完整的API列表请参考[API文档](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts)及[示例文档说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-test-kit/js-apis-uitest.md#uiwindow9)1414
1415**示例代码1**:获取窗口属性。
1416
1417```javascript
1418let window: UiWindow = await driver.findWindow({actived: true})
1419let bundelName: string = await window.getBundleName()
1420```
1421
1422**示例代码2**:移动窗口。
1423
1424```javascript
1425let window: UiWindow = await driver.findWindow({actived: true})
1426await window.moveTo(500,500)
1427```
1428
1429**示例代码3**:关闭窗口。
1430
1431```javascript
1432let window: UiWindow = await driver.findWindow({actived: true})
1433await window.close()
1434```
1435
1436### 使用方式
1437
1438  开发者可以下载Deveco Studio创建测试工程后,在其中调用框架提供接口进行相关测试操作,测试工程创建及测试脚本执行使用指南请参见[IDE指导文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568)1439  UI测试框架使能需要执行如下命令。
1440
1441>```shell
1442> hdc shell param set persist.ace.testmode.enabled 1
1443>```
1444### UI测试框架自构建方式
1445
1446> Ui测试框架在OpenHarmony-3.1-Release版本中未随版本编译,需手动处理,请参考[3.1-Release版本使用指导](https://gitee.com/openharmony/testfwk_arkxtest/blob/OpenHarmony-3.1-Release/README_zh.md#%E6%8E%A8%E9%80%81ui%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E8%87%B3%E8%AE%BE%E5%A4%87)1447
1448开发者如需自行编译Ui测试框架代码验证子修改内容,构建命令和推送位置请参考本章节内容。
1449
1450#### 构建命令
1451
1452```shell
1453./build.sh --product-name rk3568 --build-target uitestkit
1454```
1455#### 推送位置
1456
1457```shell
1458hdc target mount
1459hdc shell mount -o rw,remount /
1460hdc file send uitest /system/bin/uitest
1461hdc file send libuitest.z.so /system/lib/module/libuitest.z.so
1462hdc shell chmod +x /system/bin/uitest
1463```
1464
1465### 命令行使用说明
1466
1467  开发者可以输入如下命令来实现对应功能。
1468
14691、打印使用帮助
1470
1471```shell
1472hdc shell uitest help
1473```
1474
14752、截屏
1476
1477```
1478hdc shell uitest screenCap
1479// 默认存储路径:/data/local/tmp,文件名:时间戳 + .png。
1480hdc shell uitest screenCap -p /data/local/tmp/1.png
1481// 指定存储路径和文件名, 只支持存放在/data/local/tmp/下。
1482```
1483
14843、获取设备当前Ui控件树信息
1485
1486```shell
1487hdc shell uitest dumpLayout
1488// 默认存储路径:/data/local/tmp,文件名:时间戳 + .json。
1489hdc shell uitest screenCap -p /data/local/tmp/1.json
1490// 指定存储路径和文件名, 只支持存放在/data/local/tmp/下。
1491```
1492
14934、录制Ui操作
1494
1495```shell
1496hdc shell uitest uiRecord record
1497// 将当前执行的Ui操作记录到/data/local/tmp/layout/record.csv
1498hdc shell uitest uiRecord read
1499// 将记录的Ui操作打印出来
1500```
1501
15025、 shell命令方式注入UI模拟操作
1503> 支持操作类型:点击 双击 长按 慢滑 快滑 拖拽 输入文字 KeyEvent。
1504
1505| 配置参数名       | 配置参数含义                                  | 配置参数取值                                                                                                                                                                                                                | 示例                                                                                  |
1506|-------------|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
1507| click       | 模拟单击操作                                  | point_x (必选参数,点击x坐标点)<br/> point_y (必选参数,点击y坐标点)                                                                                                                                                                      | hdc shell uitest uiInput click point_x point_y                                      |
1508| doubleClick | 模拟双击操作                                  | point_x (必选参数,双击x坐标点)<br/> point_y (必选参数,双击y坐标点)                                                                                                                                                                      | hdc shell uitest uiInput doubleClick point_x point_y                                |
1509| longClick   | 模拟长按操作                                  | point_x (必选参数,长按x坐标点)<br/> point_y (必选参数,长按y坐标点)                                                                                                                                                                      | hdc shell uitest uiInput longClick point_x point_y                                  |
1510| fling       | 模拟快滑操作                                  | from_x (必选参数,滑动起点x坐标)<br/> from_y(必选参数,滑动起点y坐标)<br/> to_x(必选参数,滑动终点x坐标)<br/> to_y(必选参数,滑动终点y坐标)<br/> swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)<br/> stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px) | hdc shell uitest uiInput fling from_x from_y to_x to_y swipeVelocityPps_ stepLength |
1511| swipe       | 模拟慢滑操作                                  | from_x (必选参数,滑动起点x坐标)<br/> from_y(必选参数,滑动起点y坐标)<br/> to_x(必选参数,滑动终点x坐标)<br/> to_y(必选参数,滑动终点y坐标)<br/> swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s))                                               | hdc shell uitest uiInput swipe from_x from_y to_x to_y swipeVelocityPps_            |
1512| drag        | 模拟拖拽操作                                  | from_x (必选参数,拖拽起点x坐标)<br/> from_y(必选参数,拖拽起点y坐标)<br/> to_x(必选参数,拖拽终点x坐标)<br/> to_y(必选参数,拖拽终点y坐标)<br/> swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s))                                               | hdc shell uitest uiInput drag from_x from_y to_x to_y swipeVelocityPps_             |
1513| dircFling   | 模拟指定方向滑动操作                              | direction (可选参数,滑动方向,可选值: [0,1,2,3], 滑动方向: [左,右,上,下],默认值: 0)<br/> swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)<br/> stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px)                                    | hdc shell uitest uiInput dircFling direction swipeVelocityPps_ stepLength                                       |
1514| inputText        | 模拟输入框输入文本操作                             | point_x (必选参数,输入框x坐标点)<br/> point_y (必选参数,输入框y坐标点)<br/> input(输入文本)                                                                                                                                                   | hdc shell uitest uiInput inputText  point_x point_y text                                 |
1515| keyEvent    | 模拟实体按键事件(如:键盘,电源键,返回上一级,返回桌面等),以及组合按键操作 | keyID (必选参数,实体按键对应ID)<br/> keyID2 (可选参数,实体按键对应ID)                                                                                                                                                                     | hdc shell uitest uiInput keyEvent keyID                                             |
1516
1517示例代码1:执行点击事件。
1518```shell
1519 hdc shell uitest uiInput click 100 100
1520```
1521示例代码2:执行双击事件。
1522```shell
1523 hdc shell uitest uiInput doubleClick 100 100
1524```
1525示例代码3:执行长按事件。
1526```shell
1527 hdc shell uitest uiInput longClick 100 100
1528```
1529示例代码4:执行快滑操作。
1530```shell
1531hdc shell uitest uiInput fling 10 10 200 200 500
1532```
1533示例代码5:执行慢滑操作。
1534```shell
1535hdc shell uitest uiInput swipe 10 10 200 200 500
1536```
1537示例代码6:执行拖拽操作。
1538```shell
1539hdc shell uitest uiInput drag 10 10 100 100 500
1540```
1541示例代码7:执行向左滑动操作。
1542```shell
1543hdc shell uitest uiInput dircFling 0 500
1544```
1545示例代码8:执行向右滑动操作。
1546```shell
1547hdc shell uitest uiInput dircFling 1 600
1548```
1549示例代码9:执行向上滑动操作。
1550```shell
1551hdc shell uitest uiInput dircFling 2
1552```
1553示例代码10:执行向下滑动操作。
1554```shell
1555hdc shell uitest uiInput dircFling 3
1556```
1557
1558示例代码11:执行输入框输入操作。
1559```shell
1560hdc shell uitest uiInput inputText 100 100 hello
1561```
1562
1563示例代码12:执行返回主页操作。
1564```shell
1565hdc shell uitest uiInput keyEvent Home
1566```
1567示例代码13:执行返回上一步操作。
1568```shell
1569hdc shell uitest uiInput keyEvent Back
1570```
1571示例代码14:执行组合键粘贴操作。
1572```shell
1573hdc shell uitest uiInput keyEvent 2072 2038
1574```
1575
1576### 版本信息
1577
1578| 版本号  | 功能说明                                                     |
1579| :------ | :----------------------------------------------------------- |
1580| 3.2.2.1 | 1、增加抛滑、获取/设置屏幕方向接口<br />2、窗口处理逻辑增加不支持场景处理逻辑 |
1581| 3.2.3.0 | 1、滑动控件进行滑动查找、滑动到尾部/顶部功能优化             |
1582| 3.2.4.0 | 1、接口调用异常时会抛出错误码                                |
1583| 3.2.5.0 | 1、通信机制变更                                              |
1584| 3.2.6.0 | 1、增加模拟鼠标操作能力接口<br />2、增加指定应用的窗口下查找目标控件接口 |
1585| 4.0.1.1 | 1、支持在daemon运行时执行uitest dumpLayout                   |
1586| 4.0.1.2 | 1、模拟鼠标动作、键鼠协同功能优化                            |
1587| 4.0.1.3 | 1、示例代码更新<br />2、滑动控件进行滑动查找、滑动到尾部/顶部功能优化 |
1588| 4.0.1.4 | 1、可选参数传入undefined时,当作默认值处理                   |
1589| 4.0.2.0 | 1、支持监听toast和dialog控件出现,使用callback的形式返回结果。 |
1590| 4.0.3.0 | 1、增加加载运行.abc文件机制。                                |
1591| 4.0.4.0 | 1、支持abc_loader框架获取UI操作录制数据,屏幕数据,控件树等,并以callback的形式返回结果<br />2、修改录制数据结构 |
1592| 4.1.1.1 | 1、对接批量获取控件信息能力,缩短获取控件信息的耗时。        |
1593| 4.1.2.0 | 1、增加shell命令方式注入UI模拟操作。                         |
1594| 4.1.3.0 | 1、新增命令行功能,uitest dumuLayout -a ,dump信息中包含控件的背景色、字体颜色/大小信息。 |
1595| 4.1.4.0 | 1、dump信息中增加hint与description字段。<br />2、优化多指操作。<br />3、优化查找控件的效率。<br />4、uitest uiInput执行效率提升。 |
1596| 5.0.1.0 | 1、优化swipe操作。<br />2、inputText输入中文的实现方式改为设置剪贴板数据后,长按控件点击粘贴。 |
1597