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#### 异步代码测试 304 305 **异步测试错误示例代码:** 306```javascript 307import { describe, it, expect } from '@ohos/hypium'; 308 309async function callBack(fn: Function) { 310 setTimeout(fn, 5000, 'done') 311} 312 313export default function callBackErrorTest() { 314 describe('callBackErrorTest', () => { 315 it('callBackErrorTest', 0, () => { 316 callBack((result: string) => { 317 try { 318 // 用例失败 319 expect().assertFail(); 320 } catch (e) { 321 } finally { 322 } 323 }) 324 }) 325 }) 326} 327``` 328> - 上述测试用例中,测试函数结束后, 回调函数才执行, 导致用例结果错误。 329> - 当使用框架测试异步代码时,框架需要知道它测试的代码何时完成。以确保测试用例结果正常统计,测试框架用以下俩种方式来处理这个问题。 330 331##### Async/Await 332> 使用 Async关键字定义一个异步测试函数,在测试函数中使用await等待测试函数完成。 333 334**Promise示例代码:** 335 336```javascript 337import { describe, it, expect } from '@ohos/hypium'; 338 339async function method_1() { 340 return new Promise<string>((res: Function, rej: Function) => { 341 //做一些异步操作 342 setTimeout(() => { 343 console.log('执行'); 344 res('method_1_call'); 345 }, 5000); 346 }); 347} 348 349export default function abilityTest() { 350 describe('ActsAbilityTest', () => { 351 it('assertContain', 0, async () => { 352 let result = await method_1(); 353 expect(result).assertEqual('method_1_call'); 354 }) 355 }) 356} 357``` 358##### done 函数 359> - done函数是测试函数的一个可选回调参数,在测试用例中手动调用,测试框架将等待done回调被调用,然后才完成测试。 360> - 当测试函数中定义done函数参数时,测试用例中必须手动调用done函数,否则用例失败会出现超时错误。 361 362 363**Promise回调示例代码:** 364```javascript 365import { describe, it, expect } from '@ohos/hypium'; 366async function method_1() { 367 return new Promise<string>((res: Function, rej: Function) => { 368 //做一些异步操作 369 setTimeout(() => { 370 console.log('执行'); 371 res('method_1_call'); 372 }, 5000); 373 }); 374} 375 376export default function abilityTest() { 377 describe('Promise_Done', () => { 378 it('Promise_Done', 0,(done: Function) => { 379 method_1().then((result: string) => { 380 try { 381 expect(result).assertEqual('method_1_call'); 382 } catch (e) { 383 } finally { 384 // 调用done函数,用例执行完成,必须手动调用done函数,否则出现超时错误。 385 done() 386 } 387 }) 388 389 }) 390 }) 391} 392``` 393 394**回调函数示例代码:** 395```javascript 396import { describe, it, expect } from '@ohos/hypium'; 397 398async function callBack(fn: Function) { 399 setTimeout(fn, 5000, 'done') 400} 401 402export default function callBackTestTest() { 403 describe('CallBackTest', () => { 404 it('CallBackTest_001', 0, (done: Function) => { 405 callBack( (result: string) => { 406 try { 407 expect(result).assertEqual('done'); 408 } catch (e) { 409 } finally { 410 // 调用done函数,用例执行完成,必须手动调用done函数,否则出现超时错误。 411 done() 412 } 413 }) 414 }) 415 }) 416} 417``` 418#### Mock能力 419 420##### 约束限制 421 422单元测试框架Mock能力从npm包[1.0.1版本](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fhypium)开始支持,需修改源码工程中package.info中配置依赖npm包版本号后使用。 423> - 仅支持mock自定义对象,不支持mock系统API对象。 424> - 不支持mock对象的私有函数。 425- **接口列表:** 426 427| No. | API | 功能说明 | 428| --- | --- |-------------------------------------------------------------------------------------------------------------------------------------------------| 429| 1 | mockFunc(obj: object, f:function()) | mock某个类的对象obj的函数f,那么需要传两个参数:obj和f,支持使用异步函数(说明:对mock而言原函数实现是同步或异步没太多区别,因为mock并不关注原函数的实现)。 | 430| 2 | when(mockedfunc:function) | 对传入后方法做检查,检查是否被mock并标记过,返回的是一个方法声明。 | 431| 3 | afterReturn(x:value) | 设定预期返回一个自定义的值value,比如某个字符串或者一个promise。 | 432| 4 | afterReturnNothing() | 设定预期没有返回值,即 undefined。 | 433| 5 | afterAction(x:action) | 设定预期返回一个函数执行的操作。 | 434| 6 | afterThrow(x:msg) | 设定预期抛出异常,并指定异常msg。 | 435| 7 | clear(obj: object) | 用例执行完毕后,进行数据mocker对象的还原处理(还原之后对象恢复被mock之前的功能)。 | 436| 8 | any | 设定用户传任何类型参数(undefined和null除外),执行的结果都是预期的值,使用ArgumentMatchers.any方式调用。 | 437| 9 | anyString | 设定用户传任何字符串参数,执行的结果都是预期的值,使用ArgumentMatchers.anyString方式调用。 | 438| 10 | anyBoolean | 设定用户传任何boolean类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyBoolean方式调用。 | 439| 11 | anyFunction | 设定用户传任何function类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyFunction方式调用。 | 440| 12 | anyNumber | 设定用户传任何数字类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyNumber方式调用。 | 441| 13 | anyObj | 设定用户传任何对象类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyObj方式调用。 | 442| 14 | matchRegexs(Regex) | 设定用户传任何正则表达式类型参数Regex,执行的结果都是预期的值,使用ArgumentMatchers.matchRegexs(Regex)方式调用。 | 443| 15 | verify(methodName, argsArray) | 验证methodName(函数名字符串)所对应的函数和其参数列表argsArray的执行行为是否符合预期,返回一个VerificationMode:一个提供验证模式的类,它有times(count)、once()、atLeast(x)、atMost(x)、never()等函数可供选择。 | 444| 16 | times(count) | 验证行为调用过count次。 | 445| 17 | once() | 验证行为调用过一次。 | 446| 18 | atLeast(count) | 验证行为至少调用过count次。 | 447| 19 | atMost(count) | 验证行为至多调用过count次。 | 448| 20 | never | 验证行为从未发生过。 | 449| 21 | ignoreMock(obj, method) | 使用ignoreMock可以还原obj对象中被mock后的函数,对被mock后的函数有效。 | 450| 22 | clearAll() | 用例执行完毕后,进行数据和内存清理,不会还原obj对象中被mock后的函数。 | | 451 452- **使用示例:** 453 454用户可以通过以下方式进行引入mock模块进行测试用例编写: 455 456- **须知:** 457使用时候必须引入的mock能力模块: MockKit,when 458根据自己用例需要引入断言能力api 459例如:`import { describe, expect, it, MockKit, when} from '@ohos/hypium'` 460 461**示例1: afterReturn 的使用** 462 463```javascript 464import { describe, expect, it, MockKit, when } from '@ohos/hypium'; 465 466class ClassName { 467 constructor() { 468 } 469 470 method_1(arg: string) { 471 return '888888'; 472 } 473 474 method_2(arg: string) { 475 return '999999'; 476 } 477} 478export default function afterReturnTest() { 479 describe('afterReturnTest', () => { 480 it('afterReturnTest', 0, () => { 481 console.info("it1 begin"); 482 // 1.创建一个mock能力的对象MockKit 483 let mocker: MockKit = new MockKit(); 484 // 2.定类ClassName,里面两个函数,然后创建一个对象claser 485 let claser: ClassName = new ClassName(); 486 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 487 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 488 // 4.期望claser.method_1函数被mock后, 以'test'为入参时调用函数返回结果'1' 489 when(mockfunc)('test').afterReturn('1'); 490 // 5.对mock后的函数进行断言,看是否符合预期 491 // 执行成功案例,参数为'test' 492 expect(claser.method_1('test')).assertEqual('1'); // 执行通过 493 }) 494 }) 495} 496``` 497- **须知:** 498`when(mockfunc)('test').afterReturn('1');` 499这句代码中的`('test')`是mock后的函数需要传递的匹配参数,目前支持传递多个参数。 500`afterReturn('1')`是用户需要预期返回的结果。 501有且只有在参数是`('test')`的时候,执行的结果才是用户自定义的预期结果。 502 503**示例2: afterReturnNothing 的使用** 504 505```javascript 506import { describe, expect, it, MockKit, when } from '@ohos/hypium'; 507 508class ClassName { 509 constructor() { 510 } 511 512 method_1(arg: string) { 513 return '888888'; 514 } 515 516 method_2(arg: string) { 517 return '999999'; 518 } 519} 520export default function afterReturnNothingTest() { 521 describe('afterReturnNothingTest', () => { 522 it('testMockfunc', 0, () => { 523 console.info("it1 begin"); 524 // 1.创建一个mock能力的对象MockKit 525 let mocker: MockKit = new MockKit(); 526 // 2.定类ClassName,里面两个函数,然后创建一个对象claser 527 let claser: ClassName = new ClassName(); 528 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 529 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 530 // 4.期望claser.method_1函数被mock后, 以'test'为入参时调用函数返回结果undefined 531 when(mockfunc)('test').afterReturnNothing(); 532 // 5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 533 // 执行成功案例,参数为'test',这时候执行原对象claser.method_1的方法,会发生变化 534 // 这时候执行的claser.method_1不会再返回'888888',而是设定的afterReturnNothing()生效// 不返回任何值; 535 expect(claser.method_1('test')).assertUndefined(); // 执行通过 536 }) 537 }) 538} 539``` 540 541**示例3: 设定参数类型为any ,即接受任何参数(undefine和null除外)的使用** 542 543 544- **须知:** 545需要引入ArgumentMatchers类,即参数匹配器,例如:ArgumentMatchers.any 546 547```javascript 548import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 549 550class ClassName { 551 constructor() { 552 } 553 554 method_1(arg: string) { 555 return '888888'; 556 } 557 558 method_2(arg: string) { 559 return '999999'; 560 } 561} 562export default function argumentMatchersAnyTest() { 563 describe('argumentMatchersAnyTest', () => { 564 it('testMockfunc', 0, () => { 565 console.info("it1 begin"); 566 // 1.创建一个mock能力的对象MockKit 567 let mocker: MockKit = new MockKit(); 568 // 2.定类ClassName,里面两个函数,然后创建一个对象claser 569 let claser: ClassName = new ClassName(); 570 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 571 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 572 // 4.期望claser.method_1函数被mock后, 以任何参数调用函数时返回结果'1' 573 when(mockfunc)(ArgumentMatchers.any).afterReturn('1'); 574 // 5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 575 // 执行成功的案例1,传参为字符串类型 576 expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。 577 // 执行成功的案例2,传参为数字类型123 578 expect(claser.method_1("123")).assertEqual('1');// 用例执行通过。 579 // 执行成功的案例3,传参为boolean类型true 580 expect(claser.method_1("true")).assertEqual('1');// 用例执行通过。 581 }) 582 }) 583} 584``` 585 586**示例4: 设定参数类型ArgumentMatchers的使用** 587 588```javascript 589import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 590 591class ClassName { 592 constructor() { 593 } 594 595 method_1(arg: string) { 596 return '888888'; 597 } 598 599 method_2(arg: string) { 600 return '999999'; 601 } 602} 603export default function argumentMatchersTest() { 604 describe('argumentMatchersTest', () => { 605 it('testMockfunc', 0, () => { 606 console.info("it1 begin"); 607 // 1.创建一个mock能力的对象MockKit 608 let mocker: MockKit = new MockKit(); 609 // 2.定类ClassName,里面两个函数,然后创建一个对象claser 610 let claser: ClassName = new ClassName(); 611 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 612 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 613 // 4.期望claser.method_1函数被mock后, 以任何string类型为参数调用函数时返回结果'1' 614 when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1'); 615 // 4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 616 // 执行成功的案例,传参为字符串类型 617 expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。 618 expect(claser.method_1('abc')).assertEqual('1'); // 用例执行通过。 619 }) 620 }) 621} 622``` 623 624**示例5: 设定参数类型为matchRegexs(Regex)等 的使用** 625```javascript 626import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 627 628class ClassName { 629 constructor() { 630 } 631 632 method_1(arg: string) { 633 return '888888'; 634 } 635 636 method_2(arg: string) { 637 return '999999'; 638 } 639} 640export default function matchRegexsTest() { 641 describe('matchRegexsTest', () => { 642 it('testMockfunc', 0, () => { 643 console.info("it1 begin"); 644 // 1.创建一个mock能力的对象MockKit 645 let mocker: MockKit = new MockKit(); 646 let claser: ClassName = new ClassName(); 647 // 2.进行mock操作,比如需要对ClassName类的method_1函数进行mock 648 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 649 // 3.期望claser.method_1函数被mock后, 以"test"为入参调用函数时返回结果'1' 650 when(mockfunc)(ArgumentMatchers.matchRegexs(new RegExp("test"))).afterReturn('1'); 651 // 4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 652 // 执行成功的案例,传参为字符串类型 653 expect(claser.method_1('test')).assertEqual('1'); // 用例执行通过。 654 }) 655 }) 656} 657``` 658 659**示例6: 验证功能 Verify函数的使用** 660```javascript 661import { describe, it, MockKit } from '@ohos/hypium'; 662 663class ClassName { 664 constructor() { 665 } 666 667 method_1(...arg: string[]) { 668 return '888888'; 669 } 670 671 method_2(...arg: string[]) { 672 return '999999'; 673 } 674} 675export default function verifyTest() { 676 describe('verifyTest', () => { 677 it('testMockfunc', 0, () => { 678 console.info("it1 begin"); 679 // 1.创建一个mock能力的对象MockKit 680 let mocker: MockKit = new MockKit(); 681 // 2.然后创建一个对象claser 682 let claser: ClassName = new ClassName(); 683 // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 684 mocker.mockFunc(claser, claser.method_1); 685 mocker.mockFunc(claser, claser.method_2); 686 // 4.方法调用如下 687 claser.method_1('abc', 'ppp'); 688 claser.method_1('abc'); 689 claser.method_1('xyz'); 690 claser.method_1(); 691 claser.method_1('abc', 'xxx', 'yyy'); 692 claser.method_1(); 693 claser.method_2('111'); 694 claser.method_2('111', '222'); 695 // 5.现在对mock后的两个函数进行验证,验证method_2,参数为'111'执行过一次 696 mocker.verify('method_2',['111']).once(); // 执行success 697 }) 698 }) 699} 700``` 701 702**示例7: ignoreMock(obj, method) 忽略函数的使用** 703```javascript 704import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 705 706class ClassName { 707 constructor() { 708 } 709 710 method_1(...arg: number[]) { 711 return '888888'; 712 } 713 714 method_2(...arg: number[]) { 715 return '999999'; 716 } 717} 718export default function ignoreMockTest() { 719 describe('ignoreMockTest', () => { 720 it('testMockfunc', 0, () => { 721 console.info("it1 begin"); 722 // 1.创建一个mock能力的对象MockKit 723 let mocker: MockKit = new MockKit(); 724 // 2.创建一个对象claser 725 let claser: ClassName = new ClassName(); 726 // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 727 let func_1: Function = mocker.mockFunc(claser, claser.method_1); 728 let func_2: Function = mocker.mockFunc(claser, claser.method_2); 729 // 4.期望claser.method_1函数被mock后, 以number类型为入参时调用函数返回结果'4' 730 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 731 // 4.期望claser.method_2函数被mock后, 以number类型为入参时调用函数返回结果'5' 732 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 733 // 5.方法调用如下 734 expect(claser.method_1(123)).assertEqual("4"); 735 expect(claser.method_2(456)).assertEqual("5"); 736 // 6.现在对mock后的两个函数的其中一个函数method_1进行忽略处理(原理是就是还原) 737 mocker.ignoreMock(claser, claser.method_1); 738 // 7.然后再去调用 claser.method_1函数,用断言测试結果 739 expect(claser.method_1(123)).assertEqual('888888'); 740 }) 741 }) 742} 743``` 744 745**示例8: clear(obj)函数的使用** 746 747```javascript 748import { describe, expect, it, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 749 750class ClassName { 751 constructor() { 752 } 753 754 method_1(...arg: number[]) { 755 return '888888'; 756 } 757 758 method_2(...arg: number[]) { 759 return '999999'; 760 } 761} 762export default function clearTest() { 763 describe('clearTest', () => { 764 it('testMockfunc', 0, () => { 765 console.info("it1 begin"); 766 // 1.创建一个mock能力的对象MockKit 767 let mocker: MockKit = new MockKit(); 768 // 2.创建一个对象claser 769 let claser: ClassName = new ClassName(); 770 // 3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 771 let func_1: Function = mocker.mockFunc(claser, claser.method_1); 772 let func_2: Function = mocker.mockFunc(claser, claser.method_2); 773 // 4.期望claser.method_1函数被mock后, 以任何number类型为参数调用函数时返回结果'4' 774 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 775 // 4.期望claser.method_2函数被mock后, 以任何number类型为参数调用函数时返回结果'5' 776 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 777 // 5.方法调用如下 778 expect(claser.method_1(123)).assertEqual('4'); 779 expect(claser.method_2(123)).assertEqual('5'); 780 // 6.清除obj上所有的mock能力(原理是就是还原) 781 mocker.clear(claser); 782 // 7.然后再去调用 claser.method_1,claser.method_2 函数,测试结果 783 expect(claser.method_1(123)).assertEqual('888888'); 784 expect(claser.method_2(123)).assertEqual('999999'); 785 }) 786 }) 787} 788``` 789 790**示例9: afterThrow(msg)函数的使用** 791 792```javascript 793import { describe, expect, it, MockKit, when } from '@ohos/hypium'; 794 795class ClassName { 796 constructor() { 797 } 798 799 method_1(arg: string) { 800 return '888888'; 801 } 802} 803export default function afterThrowTest() { 804 describe('afterThrowTest', () => { 805 it('testMockfunc', 0, () => { 806 console.info("it1 begin"); 807 // 1.创建一个mock能力的对象MockKit 808 let mocker: MockKit = new MockKit(); 809 // 2.创建一个对象claser 810 let claser: ClassName = new ClassName(); 811 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 812 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 813 // 4.期望claser.method_1函数被mock后, 以'test'为参数调用函数时抛出error xxx异常 814 when(mockfunc)('test').afterThrow('error xxx'); 815 // 5.执行mock后的函数,捕捉异常并使用assertEqual对比msg否符合预期 816 try { 817 claser.method_1('test'); 818 } catch (e) { 819 expect(e).assertEqual('error xxx'); // 执行通过 820 } 821 }) 822 }) 823} 824``` 825 826**示例10: mock异步返回promise对象的使用** 827 828```javascript 829import { describe, expect, it, MockKit, when } from '@ohos/hypium'; 830 831class ClassName { 832 constructor() { 833 } 834 835 async method_1(arg: string) { 836 return new Promise<string>((resolve: Function, reject: Function) => { 837 setTimeout(() => { 838 console.log('执行'); 839 resolve('数据传递'); 840 }, 2000); 841 }); 842 } 843} 844export default function mockPromiseTest() { 845 describe('mockPromiseTest', () => { 846 it('testMockfunc', 0, async (done: Function) => { 847 console.info("it1 begin"); 848 // 1.创建一个mock能力的对象MockKit 849 let mocker: MockKit = new MockKit(); 850 // 2.创建一个对象claser 851 let claser: ClassName = new ClassName(); 852 // 3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 853 let mockfunc: Function = mocker.mockFunc(claser, claser.method_1); 854 // 4.期望claser.method_1函数被mock后, 以'test'为参数调用函数时返回一个promise对象 855 when(mockfunc)('test').afterReturn(new Promise<string>((resolve: Function, reject: Function) => { 856 console.log("do something"); 857 resolve('success something'); 858 })); 859 // 5.执行mock后的函数,即对定义的promise进行后续执行 860 let result = await claser.method_1('test'); 861 expect(result).assertEqual("success something"); 862 done(); 863 }) 864 }) 865} 866``` 867 868**示例11:verify times函数的使用(验证函数调用次数)** 869 870```javascript 871import { describe, it, MockKit, when } from '@ohos/hypium' 872 873class ClassName { 874 constructor() { 875 } 876 877 method_1(...arg: string[]) { 878 return '888888'; 879 } 880} 881export default function verifyTimesTest() { 882 describe('verifyTimesTest', () => { 883 it('test_verify_times', 0, () => { 884 // 1.创建MockKit对象 885 let mocker: MockKit = new MockKit(); 886 // 2.创建类对象 887 let claser: ClassName = new ClassName(); 888 // 3.mock 类ClassName对象的某个方法,比如method_1 889 let func_1: Function = mocker.mockFunc(claser, claser.method_1); 890 // 4.期望被mock后的函数返回结果'4' 891 when(func_1)('123').afterReturn('4'); 892 // 5.随机执行几次函数,参数如下 893 claser.method_1('123', 'ppp'); 894 claser.method_1('abc'); 895 claser.method_1('xyz'); 896 claser.method_1(); 897 claser.method_1('abc', 'xxx', 'yyy'); 898 claser.method_1('abc'); 899 claser.method_1(); 900 // 6.验证函数method_1且参数为'abc'时,执行过的次数是否为2 901 mocker.verify('method_1', ['abc']).times(2); 902 }) 903 }) 904} 905``` 906 907 908**示例12:verify atLeast函数的使用(验证函数调用次数)** 909 910```javascript 911import { describe, it, MockKit, when } from '@ohos/hypium' 912 913class ClassName { 914 constructor() { 915 } 916 917 method_1(...arg: string[]) { 918 return '888888'; 919 } 920} 921export default function verifyAtLeastTest() { 922 describe('verifyAtLeastTest', () => { 923 it('test_verify_atLeast', 0, () => { 924 // 1.创建MockKit对象 925 let mocker: MockKit = new MockKit(); 926 // 2.创建类对象 927 let claser: ClassName = new ClassName(); 928 // 3.mock 类ClassName对象的某个方法,比如method_1 929 let func_1: Function = mocker.mockFunc(claser, claser.method_1); 930 // 4.期望被mock后的函数返回结果'4' 931 when(func_1)('123').afterReturn('4'); 932 // 5.随机执行几次函数,参数如下 933 claser.method_1('123', 'ppp'); 934 claser.method_1('abc'); 935 claser.method_1('xyz'); 936 claser.method_1(); 937 claser.method_1('abc', 'xxx', 'yyy'); 938 claser.method_1(); 939 // 6.验证函数method_1且参数为空时,是否至少执行过2次 940 mocker.verify('method_1', []).atLeast(2); 941 }) 942 }) 943} 944``` 945 946**示例13:mock静态函数** 947> @since1.0.16 支持 948 949```javascript 950import { describe, it, expect, MockKit, when, ArgumentMatchers } from '@ohos/hypium'; 951 952class ClassName { 953 constructor() { 954 } 955 956 static method_1() { 957 return 'ClassName_method_1_call'; 958 } 959} 960 961export default function staticTest() { 962 describe('staticTest', () => { 963 it('staticTest_001', 0, () => { 964 let really_result = ClassName.method_1(); 965 expect(really_result).assertEqual('ClassName_method_1_call'); 966 // 1.创建MockKit对象 967 let mocker: MockKit = new MockKit(); 968 // 2.mock 类ClassName对象的某个方法,比如method_1 969 let func_1: Function = mocker.mockFunc(ClassName, ClassName.method_1); 970 // 3.期望被mock后的函数返回结果'mock_data' 971 when(func_1)(ArgumentMatchers.any).afterReturn('mock_data'); 972 let mock_result = ClassName.method_1(); 973 expect(mock_result).assertEqual('mock_data'); 974 // 清除mock能力 975 mocker.clear(ClassName); 976 let really_result1 = ClassName.method_1(); 977 expect(really_result1).assertEqual('ClassName_method_1_call'); 978 }) 979 }) 980} 981``` 982 983#### 数据驱动 984 985##### 约束限制 986 987单元测试框架数据驱动能力从[框架 1.0.2版本](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fhypium)开始支持。 988 989- 数据参数传递 : 为指定测试套、测试用例传递测试输入数据参数。 990- 压力测试 : 为指定测试套、测试用例设置执行次数。 991 992数据驱动可以根据配置参数来驱动测试用例的执行次数和每一次传入的参数,使用时依赖data.json配置文件,文件内容如下: 993 994>说明 : data.json与测试用例*.test.js|ets文件同目录 995 996```json 997{ 998 "suites": [{ 999 "describe": ["actsAbilityTest"], 1000 "stress": 2, 1001 "params": { 1002 "suiteParams1": "suiteParams001", 1003 "suiteParams2": "suiteParams002" 1004 }, 1005 "items": [{ 1006 "it": "testDataDriverAsync", 1007 "stress": 2, 1008 "params": [{ 1009 "name": "tom", 1010 "value": 5 1011 }, { 1012 "name": "jerry", 1013 "value": 4 1014 }] 1015 }, { 1016 "it": "testDataDriver", 1017 "stress": 3 1018 }] 1019 }] 1020} 1021``` 1022 1023配置参数说明: 1024 1025| | 配置项名称 | 功能 | 必填 | 1026| :--- | :--------- | :------------------------------------ | ---- | 1027| 1 | "suite" | 测试套配置 。 | 是 | 1028| 2 | "items" | 测试用例配置 。 | 是 | 1029| 3 | "describe" | 测试套名称 。 | 是 | 1030| 4 | "it" | 测试用例名称 。 | 是 | 1031| 5 | "params" | 测试套 / 测试用例 可传入使用的参数 。 | 否 | 1032| 6 | "stress" | 测试套 / 测试用例 指定执行次数 。 | 否 | 1033 1034示例代码: 1035 1036DevEco Studio从V3.0 Release(2022-09-06)版本开始支持 1037 1038stage模型: 1039 1040在TestAbility目录下TestAbility.ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据 1041 1042FA模型: 1043 1044在TestAbility目录下app.js或app.ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据 1045 1046```javascript 1047import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' 1048import { Hypium } from '@ohos/hypium' 1049import testsuite from '../test/List.test' 1050import data from '../test/data.json'; 1051 1052... 1053Hypium.setData(data); 1054Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite); 1055... 1056``` 1057 1058```javascript 1059 import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 1060 1061 export default function abilityTest() { 1062 describe('actsAbilityTest', () => { 1063 it('testDataDriverAsync', 0, async (done: Function, data: ParmObj) => { 1064 console.info('name: ' + data.name); 1065 console.info('value: ' + data.value); 1066 done(); 1067 }); 1068 1069 it('testDataDriver', 0, () => { 1070 console.info('stress test'); 1071 }) 1072 }) 1073} 1074 interface ParmObj { 1075 name: string, 1076 value: string 1077 } 1078``` 1079>说明 : 若要使用数据驱动传入参数功能,测试用例it的func必须传入两个参数:done定义在前面,data定义在后面;若不使用数据驱动传入参数功能,func可以不传参或传入done 1080 1081正确示例: 1082```javascript 1083 it('testcase01', 0, async (done: Function, data: ParmObj) => { 1084 ... 1085 done(); 1086 }); 1087 it('testcase02', 0, async (done: Function) => { 1088 ... 1089 done(); 1090 }); 1091 it('testcase03', 0, () => { 1092 ... 1093 }); 1094``` 1095错误示例: 1096```javascript 1097 it('testcase01', 0, async (data: ParmObj, done: Function) => { 1098 ... 1099 done(); 1100 }); 1101 it('testcase02', 0, async (data: ParmObj) => { 1102 ... 1103 }); 1104``` 1105 1106#### 专项能力 1107 1108该项能力需通过在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) 1109 1110- **筛选能力** 1111 1112 1、按测试用例属性筛选 1113 1114 可以利用框架提供的Level、Size、TestType 对象,对测试用例进行标记,以区分测试用例的级别、粒度、测试类型,各字段含义及代码如下: 1115 1116 | Key | 含义说明 | Value取值范围 | 1117 | -------- | ------------ | ------------------------------------------------------------ | 1118 | level | 用例级别 | "0","1","2","3","4", 例如:-s level 1 | 1119 | size | 用例粒度 | "small","medium","large", 例如:-s size small | 1120 | testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function | 1121 1122 示例代码: 1123 1124 ```javascript 1125 import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium'; 1126 1127 export default function attributeTest() { 1128 describe('attributeTest', () => { 1129 it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => { 1130 console.info('Hello Test'); 1131 }) 1132 }) 1133} 1134 ``` 1135 1136 示例命令: 1137 1138 ```shell 1139 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s testType function -s size small -s level 0 1140 ``` 1141 1142 该命令作用是筛选测试应用中同时满足,用例测试类型是“function”、用例粒度是“small”、用例级别是“0”的三个条件用例执行。 1143 1144 2、按测试套/测试用例名称筛选 1145 1146 注意:测试套和测试用例的命名要符合框架规则,即以字母开头,后跟一个或多个字母、数字,不能包含特殊符号。 1147 1148 框架可以通过指定测试套与测试用例名称,来指定特定用例的执行,测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔 1149 1150 | Key | 含义说明 | Value取值范围 | 1151 | -------- | ----------------------- | ------------------------------------------------------------ | 1152 | class | 指定要执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt | 1153 | notClass | 指定不执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttribut | 1154 1155 示例代码: 1156 1157 ```javascript 1158 import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium'; 1159 1160 export default function attributeTest() { 1161 describe('describeTest_000', () => { 1162 it("testIt_00", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => { 1163 console.info('Hello Test'); 1164 }) 1165 1166 it("testIt_01", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => { 1167 console.info('Hello Test'); 1168 }) 1169 }) 1170 1171 describe('describeTest_001', () => { 1172 it("testIt_02", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => { 1173 console.info('Hello Test'); 1174 }) 1175 }) 1176} 1177 ``` 1178 1179 示例命令1: 1180 1181 ```shell 1182 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s class describeTest_000#testIt_00,describeTest_001 1183 ``` 1184 1185 该命令作用是执行“describeTest_001”测试套中所用用例,以及“describeTest_000”测试套中的“testIt_00”用例。 1186 1187 示例命令2: 1188 1189 ```shell 1190 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s notClass describeTest_000#testIt_01 1191 ``` 1192 1193 该命令作用是不执行“describeTest_000”测试套中的“testIt_01”用例。 1194 1195- **随机执行** 1196 1197 使测试套与测试用例随机执行,用于稳定性测试。 1198 1199 | Key | 含义说明 | Value取值范围 | 1200 | ------ | ------------------------------------ | ---------------------------------------------- | 1201 | random | @since1.0.3 测试套、测试用例随机执行 | true, 不传参默认为false, 例如:-s random true | 1202 1203 示例命令: 1204 1205 ```shell 1206 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s random true 1207 ``` 1208 1209- **压力测试** 1210 1211 指定要执行用例的执行次数,用于压力测试。 1212 1213 | Key | 含义说明 | Value取值范围 | 1214 | ------ | ------------------------------------ | ------------------------------ | 1215 | stress | @since1.0.5 指定要执行用例的执行次数 | 正整数, 例如: -s stress 1000 | 1216 1217 示例命令: 1218 1219 ```shell 1220 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s stress 1000 1221 ``` 1222 1223- **用例超时时间设置** 1224 1225 指定测试用例执行的超时时间,用例实际耗时如果大于超时时间,用例会抛出"timeout"异常,用例结果会显示“excute timeout XXX” 1226 1227 | Key | 含义说明 | Value取值范围 | 1228 | ------- | -------------------------- | ---------------------------------------------------- | 1229 | timeout | 指定测试用例执行的超时时间 | 正整数(单位ms),默认为 5000,例如: -s timeout 15000 | 1230 1231 示例命令: 1232 1233 ```shell 1234 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s timeout 15000 1235 ``` 1236 1237- **遇错即停模式** 1238 1239 | Key | 含义说明 | Value取值范围 | 1240 | ------------ | ------------------------------------------------------------ | ---------------------------------------------------- | 1241 | breakOnError | @since1.0.6 遇错即停模式,当执行用例断言失败或者发生错误时,退出测试执行流程 | true, 不传参默认为false, 例如:-s breakOnError true | 1242 1243 示例命令: 1244 1245 ```shell 1246 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s breakOnError true 1247 ``` 1248 1249- **测试套中用例信息输出** 1250 1251 输出测试应用中待执行的测试用例信息 1252 1253 | Key | 含义说明 | Value取值范围 | 1254 | ------ | ---------------------------- | ---------------------------------------------- | 1255 | dryRun | 显示待执行的测试用例信息全集 | true, 不传参默认为false, 例如:-s dryRun true | 1256 1257 示例命令: 1258 1259 ```shell 1260 hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s dryRun true 1261 ``` 1262 1263- **嵌套能力** 1264 1265 1.示例代码 1266 ```javascript 1267 // Test1.test.ets 1268 import { describe, expect, it } from '@ohos/hypium'; 1269 import test2 from './Test2.test'; 1270 1271 export default function test1() { 1272 describe('test1', () => { 1273 it('assertContain1', 0, () => { 1274 let a = true; 1275 let b = true; 1276 expect(a).assertEqual(b); 1277 }) 1278 // 引入测试套test2 1279 test2(); 1280 }) 1281 } 1282 ``` 1283 1284 ```javascript 1285 //Test2.test.ets 1286 import { describe, expect, it } from '@ohos/hypium'; 1287 1288 export default function test2() { 1289 describe('test2', () => { 1290 it('assertContain1', 0, () => { 1291 let a = true; 1292 let b = true; 1293 expect(a).assertEqual(b); 1294 }) 1295 it('assertContain2', 0, () => { 1296 let a = true; 1297 let b = true; 1298 expect(a).assertEqual(b); 1299 }) 1300 }) 1301 } 1302 ``` 1303 1304 ```javascript 1305 //List.test.ets 1306 import test1 from './nest/Test1.test'; 1307 1308 export default function testsuite() { 1309 test1(); 1310 } 1311 ``` 1312 1313 2.示例筛选参数 1314 ```shell 1315 #执行test1的全部测试用例 1316 -s class test1 1317 ``` 1318 ```shell 1319 #执行test1的子测试用例 1320 -s class test1#assertContain1 1321 ``` 1322 ```shell 1323 #执行test1的子测试套test2的测试用例 1324 -s class test1.test2#assertContain1 1325 ``` 1326 1327- **跳过能力** 1328 1329 | Key | 含义说明 | Value取值范围 | 1330 | ------------ | ------------------------------------------------------------ | ---------------------------------------------------- | 1331 | skipMessage | @since1.0.17 显示待执行的测试用例信息全集中是否包含跳过测试套和跳过用例的信息 | true/false, 不传参默认为false, 例如:-s skipMessage true | 1332 | runSkipped | @since1.0.17 指定要执行的跳过测试套&跳过用例 | all,skipped,${describeName}#${itName},${describeName},不传参默认为空,例如:-s runSkipped all | 1333 1334 1.示例代码 1335 1336 ```javascript 1337 //Skip1.test.ets 1338 import { expect, xdescribe, xit } from '@ohos/hypium'; 1339 1340 export default function skip1() { 1341 xdescribe('skip1', () => { 1342 //注意:在xdescribe中不支持编写it用例 1343 xit('assertContain1', 0, () => { 1344 let a = true; 1345 let b = true; 1346 expect(a).assertEqual(b); 1347 }) 1348 }) 1349 } 1350 ``` 1351 1352 ```javascript 1353 //Skip2.test.ets 1354 import { describe, expect, xit, it } from '@ohos/hypium'; 1355 1356 export default function skip2() { 1357 describe('skip2', () => { 1358 //默认会跳过assertContain1 1359 xit('assertContain1', 0, () => { 1360 let a = true; 1361 let b = true; 1362 expect(a).assertEqual(b); 1363 }) 1364 it('assertContain2', 0, () => { 1365 let a = true; 1366 let b = true; 1367 expect(a).assertEqual(b); 1368 }) 1369 }) 1370 } 1371 ``` 1372 1373 1374 1375### 使用方式 1376 1377单元测试框架以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)。 1378>**说明** 1379> 1380>1.0.8版本开始单元测试框架以HAR(Harmony Archive)格式发布 1381> 1382> 1383 1384## Ui测试框架功能特性 1385 1386| No. | 特性 | 功能说明 | 1387| ---- |-----------|-------------------------------------------------| 1388| 1 | Driver | Ui测试的入口,提供查找控件,检查控件存在性以及注入按键能力。 | 1389| 2 | On | 用于描述目标控件特征(文本、id、类型等),`Driver`根据`On`描述的控件特征信息来查找控件。 | 1390| 3 | Component | Driver查找返回的控件对象,提供查询控件属性,滑动查找等触控和检视能力。 | 1391| 4 | UiWindow | Driver查找返回的窗口对象,提供获取窗口属性、操作窗口的能力。 | 1392 1393**使用者在测试脚本通过如下方式引入使用:** 1394 1395```typescript 1396import {Driver,ON,Component,UiWindow,MatchPattern} from '@ohos.UiTest' 1397``` 1398 1399> 须知 1400> 1. `On`类提供的接口全部是同步接口,使用者可以使用`builder`模式链式调用其接口构造控件筛选条件。 1401> 2. `Driver`和`Component`类提供的接口全部是异步接口(`Promise`形式),**需使用`await`语法**。 1402> 3. Ui测试用例均需使用**异步**语法编写用例,需遵循单元测试框架异步用例编写规范。 1403 1404 1405 1406在测试用例文件中import `On/Driver/Component`类,然后调用API接口编写测试用例。 1407 1408```javascript 1409import { Driver, ON, Component } from '@kit.TestKit' 1410import { describe, it, expect } from '@ohos/hypium' 1411 1412export default function findComponentTest() { 1413 describe('findComponentTest', () => { 1414 it('uitest_demo0', 0, async () => { 1415 // create Driver 1416 let driver: Driver = Driver.create(); 1417 // find component by text 1418 let button: Component = await driver.findComponent(ON.text('Hello World').enabled(true)); 1419 // click component 1420 await button.click(); 1421 // get and assert component text 1422 let content: string = await button.getText(); 1423 expect(content).assertEqual('Hello World'); 1424 }) 1425 }) 1426} 1427``` 1428 1429### 基于ArkTS API的测试 1430 1431 1432#### Driver使用说明 1433 1434`Driver`类作为UiTest测试框架的总入口,提供查找控件,注入按键,单击坐标,滑动控件,手势操作,截图等能力。 1435 1436| No. | API | 功能描述 | 1437| ---- |-----------------------------------------------------------------| ---------------------- | 1438| 1 | create():Promise<Driver> | 静态方法,构造Driver。 | 1439| 2 | findComponent(on:On):Promise<Component> | 查找匹配控件。 | 1440| 3 | pressBack():Promise<void> | 单击BACK键。 | 1441| 4 | click(x:number, y:number):Promise<void> | 基于坐标点的单击。 | 1442| 5 | swipe(x1:number, y1:number, x2:number, y2:number):Promise<void> | 基于坐标点的滑动。 | 1443| 6 | assertComponentExist(on:On):Promise<void> | 断言匹配的控件存在。 | 1444| 7 | delayMs(t:number):Promise<void> | 延时。 | 1445| 8 | screenCap(s:path):Promise<void> | 截屏。 | 1446| 9 | findWindow(filter: WindowFilter): Promise<UiWindow> | 查找匹配窗口。 | 1447 1448其中assertComponentExist接口是断言API,用于断言当前界面存在目标控件;如果控件不存在,该API将抛出JS异常,使当前测试用例失败。 1449 1450```javascript 1451import { describe, it} from '@ohos/hypium'; 1452import { Driver, ON } from '@kit.TestKit'; 1453 1454export default function assertComponentExistTest() { 1455 describe('assertComponentExistTest', () => { 1456 it('Uitest_demo0', 0, async (done: Function) => { 1457 try{ 1458 // create Driver 1459 let driver: Driver = Driver.create(); 1460 // assert text 'hello' exists on current Ui 1461 await driver.assertComponentExist(ON.text('hello')); 1462 } finally { 1463 done(); 1464 } 1465 }) 1466 }) 1467} 1468``` 1469 1470`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)。 1471 1472#### On使用说明 1473 1474Ui测试框架通过`On`类提供了丰富的控件特征描述API,用来匹配查找要操作或检视的目标控件。`On`提供的API能力具有以下特点: 1475 1476- 支持匹配单属性和匹配多属性组合,例如同时指定目标控件text和id。 1477- 控件属性支持多种匹配模式(等于,包含,`STARTS_WITH`,`ENDS_WITH`,`REG_EXP`,`REG_EXP_ICASE`)。 1478 1479- 支持相对定位控件,可通过`isBefore`和`isAfter`等API限定邻近控件特征进行辅助定位。 1480 1481| No. | API | 功能描述 | 1482|-----|------------------------------------|----------------------------| 1483| 1 | id(i:string):On | 指定控件id。 | 1484| 2 | text(t:string, p?:MatchPattern):On | 指定控件文本,可指定匹配模式。 | 1485| 3 | type(t:string):On | 指定控件类型。 | 1486| 4 | enabled(e:bool):On | 指定控件使能状态。 | 1487| 5 | clickable(c:bool):On | 指定控件可单击状态。 | 1488| 6 | longClickable(l:bool):On | 指定控件可长按状态。 | 1489| 7 | focused(f:bool):On | 指定控件获焦状态。 | 1490| 8 | scrollable(s:bool):On | 指定控件可滑动状态。 | 1491| 9 | selected(s:bool):On | 指定控件选中状态。 | 1492| 10 | checked(c:bool):On | 指定控件选择状态。 | 1493| 11 | checkable(c:bool):On | 指定控件可选择状态。 | 1494| 12 | isBefore(b:On):On | **相对定位**,限定目标控件位于指定特征控件之前。 | 1495| 13 | isAfter(b:On):On | **相对定位**,限定目标控件位于指定特征控件之后。 | 1496| 14 | id(i:string,p?:MatchPattern:On | 指定控件id,可指定匹配模式。 | 1497| 15 | hint(h:string, p?:MatchPattern):On | 指定控件提示文本,可指定匹配模式。 | 1498| 16 | type(t:string,p?:MatchPattern):On | 指定控件类型,可指定匹配模式。 | 1499| 17 | description(d:string,p?:MatchPattern):On | 指定控件描述文本信息,可指定匹配模式。 | 1500 1501其中,`text`,`id`,`type`,`hint`,`description`属性支持{`MatchPattern.EQUALS`,`MatchPattern.CONTAINS`,`MatchPattern.STARTS_WITH`,`MatchPattern.ENDS_WITH`,`MatchPattern.REG_EXP`,`MatchPattern.REG_EXP_ICASE`}六种匹配模式,缺省使用`MatchPattern.EQUALS`模式。 1502 1503`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)。 1504 1505##### 控件定位 1506 1507**示例代码1**:查找id是`Id_button`的控件。 1508 1509```javascript 1510let button: Component = await driver.findComponent(ON.id('Id_button')) 1511``` 1512 1513 **示例代码2**:查找id是`Id_button`并且状态是`enabled`的控件,适用于无法通过单一属性定位的场景。 1514 1515```javascript 1516let button: Component = await driver.findComponent(ON.id('Id_button').enabled(true)) 1517``` 1518 1519通过`On.id(x).enabled(y)`来指定目标控件的多个属性。 1520 1521**示例代码3**:查找文本中包含`hello`的控件,适用于不能完全确定控件属性取值的场景。 1522 1523```javascript 1524let txt: Component = await driver.findComponent(ON.text('hello', MatchPattern.CONTAINS)) 1525``` 1526 1527通过向`On.text()`方法传入第二个参数`MatchPattern.CONTAINS`来指定文本匹配规则;默认规则是`MatchPattern.EQUALS`,即目标控件text属性必须严格等于给定值。 1528 1529##### 控件相对定位 1530 1531**示例代码1**:查找位于文本控件`Item3_3`后面的,id是`Id_switch`的Switch控件。 1532 1533```javascript 1534let switch: Component = await driver.findComponent(ON.id('Id_switch').isAfter(ON.text('Item3_3'))) 1535``` 1536 1537通过`On.isAfter`方法,指定位于目标控件前面的特征控件属性,通过该特征控件进行相对定位。一般地,特征控件是某个具有全局唯一特征的控件(例如具有唯一的id或者唯一的text)。 1538 1539类似的,可以使用`On.isBefore`控件指定位于目标控件后面的特征控件属性,实现相对定位。 1540 1541#### Component使用说明 1542 1543`Component`类代表了Ui界面上的一个控件,一般是通过`Driver.findComponent(on)`方法查找到的。通过该类的实例,用户可以获取控件属性,单击控件,滑动查找,注入文本等操作。 1544 1545`Component`包含的常用API: 1546 1547| No. | API | 功能描述 | 1548|-----|------------------------------------|----------------------------| 1549| 1 | click():Promise<void> | 单击该控件。 | 1550| 2 | inputText(t:string):Promise<void> | 向控件中输入文本(适用于文本框控件)。 | 1551| 3 | scrollSearch(s:On):Promise<Component> | 在该控件上滑动查找目标控件(适用于List等控件)。 | 1552| 4 | scrollToTop(s:number):Promise<void> | 滑动到该控件顶部(适用于List等控件)。 | 1553| 5 | scrollTobottom(s:number):Promise<void> | 滑动到该控件底部(适用于List等控件)。 | 1554| 6 | getText():Promise<string> | 获取控件text。 | 1555| 7 | getId():Promise<number> | 获取控件id。 | 1556| 8 | getType():Promise<string> | 获取控件类型。 | 1557| 9 | isEnabled():Promise<bool> | 获取控件使能状态。 | 1558 1559`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)。 1560 1561**示例代码1**:单击控件。 1562 1563```javascript 1564let button: Component = await driver.findComponent(ON.id('Id_button')) 1565await button.click() 1566``` 1567 1568**示例代码2**:通过get接口获取控件属性后,可以使用单元测试框架提供的assert*接口做断言检查。 1569 1570```javascript 1571let component: Component = await driver.findComponent(ON.id('Id_title')) 1572expect(component !== null).assertTrue() 1573``` 1574 1575**示例代码3**:在List控件中滑动查找text是`Item3_3`的子控件。 1576 1577```javascript 1578let list: Component = await driver.findComponent(ON.id('Id_list')) 1579let found: Component = await list.scrollSearch(ON.text('Item3_3')) 1580expect(found).assertTrue() 1581``` 1582 1583**示例代码4**:向输入框控件中输入文本。 1584 1585```javascript 1586let editText: Component = await driver.findComponent(ON.type('InputText')) 1587await editText.inputText('user_name') 1588``` 1589#### UiWindow使用说明 1590 1591`UiWindow`类代表了Ui界面上的一个窗口,一般是通过`Driver.findWindow(WindowFilter)`方法查找到的。通过该类的实例,用户可以获取窗口属性,并进行窗口拖动、调整窗口大小等操作。 1592 1593`UiWindow`包含的常用API: 1594 1595| No. | API | 功能描述 | 1596| ---- | ------------------------------------------------------------ | -------------------------------------------------- | 1597| 1 | getBundleName(): Promise<string> | 获取窗口所属应用包名。 | 1598| 2 | getTitle(): Promise<string> | 获取窗口标题信息。 | 1599| 3 | focus(): Promise<bool> | 使得当前窗口获取焦点。 | 1600| 4 | moveTo(x: number, y: number): Promise<bool> | 将当前窗口移动到指定位置(适用于支持移动的窗口)。 | 1601| 5 | resize(wide: number, height: number, direction: ResizeDirection): Promise<bool> | 调整窗口大小(适用于支持调整大小的窗口)。 | 1602| 6 | split(): Promise<bool> | 将窗口模式切换为分屏模式(适用于支持分屏的窗口)。 | 1603| 7 | close(): Promise<bool> | 关闭当前窗口。 | 1604 1605`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)。 1606 1607**示例代码1**:获取窗口属性。 1608 1609```javascript 1610let window: UiWindow = await driver.findWindow({actived: true}) 1611let bundelName: string = await window.getBundleName() 1612``` 1613 1614**示例代码2**:移动窗口。 1615 1616```javascript 1617let window: UiWindow = await driver.findWindow({actived: true}) 1618await window.moveTo(500,500) 1619``` 1620 1621**示例代码3**:关闭窗口。 1622 1623```javascript 1624let window: UiWindow = await driver.findWindow({actived: true}) 1625await window.close() 1626``` 1627 1628#### 使用方式 1629 1630开发者可以下载Deveco Studio创建测试工程后,在其中调用框架提供接口进行相关测试操作,测试工程创建及测试脚本执行使用指南请参见[IDE指导文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568)。 1631UI测试框架使能需要执行如下命令。 1632>**说明** 1633> 1634>OpenHarmony 3.2版本需使用此命令,OpenHarmony4.0版本开始无需使用,默认使能。 1635> 1636> hdc shell param set persist.ace.testmode.enabled 1。 1637 1638### 基于shell命令测试 1639> 在开发过程中,若需要快速进行截屏、 录屏、注入UI模拟操作、获取控件树等操作,可以使用shell命令,更方便完成相应测试。 1640> 1641> **说明:** 1642> 1643> 使用cmd的方式,需要配置好hdc相关的环境变量。 1644 1645**命令列表** 1646 1647| 命令 | 配置参数 | 描述 | 1648|---------------|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 1649| help | | 显示uitest工具能够支持的命令信息。 | 1650| screenCap |[-p savePath] | 截屏。<br> **-p**:指定存储路径和文件名, 只支持存放在/data/local/tmp/下。<br> 默认存储路径:/data/local/tmp,文件名:时间戳 + .png 。 | 1651| dumpLayout |[-p savePath] <br/>[-w windowId] <br/>[-b bundleName]<br/>[-m true/false ]<br/>[-i ]<br/>[-a]| 获取当前的控件树。默认过滤不可见控件并进行窗口合并。<br> **-p** :指定存储路径和文件名, 只支持存放在/data/local/tmp/下。<br/> 默认存储路径:/data/local/tmp,文件名:时间戳 + .json。<br> **-w** :仅获取指定windowId的应用窗口。<br/> **-b** :仅获取指定bundleName的应用窗口。<br/> **-m** :是否进行窗口合并。true 代表进行合并,不使用该选项时默认进行窗口合并。<br/> **-i** :不过滤不可见控件,也不做窗口合并。<br/> **-a** :保存 BackgroundColor、 Content、FontColor、FontSize、extraAttrs 属性数据。<br/> **-a和-i** 不可同时使用。 | 1652| uiRecord | \<record/read> | 录制Ui操作。 <br> **record** :开始录制,将当前界面操作记录到/data/local/tmp/record.csv,结束录制操作使用Ctrl+C结束录制。 <br> **read** :读取并且打印录制数据。<br>各选项使用说明请参考[用户录制操作](#用户录制操作)。 | 1653| uiInput | \<help / click / doubleClick / longClick / fling / swipe / drag / dircFling / inputText / text / keyEvent> | 注入UI模拟操作。<br>各选项使用说明请参考[注入ui模拟操作](#注入ui模拟操作)。 | 1654| --version | | 获取当前工具版本号。 | 1655| start-daemon|\<token>| token:测试应用端生产的uitest链接标识。<br/>拉起uitest测试进程,与token指向的测试应用进行连接。<br/>由测试应用注入,不支持用户通过shell命令使用。 | 1656 1657 1658#### 截图使用示例 1659 1660```bash 1661# 存储路径:/data/local/tmp,文件名:时间戳 + .png。 1662hdc shell uitest screenCap 1663# 指定存储路径和文件名,存放在/data/local/tmp/下。 1664hdc shell uitest screenCap -p /data/local/tmp/1.png 1665``` 1666 1667#### 获取控件树使用示例 1668```bash 1669hdc shell uitest dumpLayout -p /data/local/tmp/1.json 1670``` 1671 1672#### 用户录制操作 1673>**说明** 1674> 1675> 录制过程中,需等待当前操作的识别结果在命令行输出后,再进行下一步操作。 1676```bash 1677# 将当前界面操作记录到/data/local/tmp/record.csv,结束录制操作使用Ctrl+C结束录制。 1678hdc shell uitest uiRecord record 1679# 读取并打印录制数据。 1680hdc shell uitest uiRecord read 1681``` 1682 1683#### 注入UI模拟操作 1684 1685| 命令 | 必填 | 描述 | 1686|------|------|-----------------| 1687| help | 是 | uiInput命令相关帮助信息。 | 1688| click | 是 | 模拟单击操作。 | 1689| doubleClick | 是 | 模拟双击操作。 | 1690| longClick | 是 | 模拟长按操作。 | 1691| fling | 是 | 模拟快滑操作。 | 1692| swipe | 是 | 模拟慢滑操作。 | 1693| drag | 是 | 模拟拖拽操作。 | 1694| dircFling | 是 | 模拟指定方向滑动操作。 | 1695| inputText | 是 | 指定坐标点,模拟输入框输入文本操作。 | 1696| text | 是 | 无需指定坐标点,在当前获焦处,模拟输入框输入文本操作。 | 1697| keyEvent | 是 | 模拟实体按键事件(如:键盘,电源键,返回上一级,返回桌面等),以及组合按键操作。 | 1698 1699##### uiInput click/doubleClick/longClick使用示例 1700 1701| 配置参数 | 必填 | 描述 | 1702|---------|------|-----------------| 1703| point_x | 是 | 点击x坐标点。 | 1704| point_y | 是 | 点击y坐标点。 | 1705 1706```shell 1707# 执行单击事件。 1708hdc shell uitest uiInput click 100 100 1709 1710# 执行双击事件。 1711hdc shell uitest uiInput doubleClick 100 100 1712 1713# 执行长按事件。 1714hdc shell uitest uiInput longClick 100 100 1715``` 1716 1717##### uiInput fling使用示例 1718 1719| 配置参数 | 必填 | 描述 | 1720|------|------------------|-----------------| 1721| from_x | 是 | 滑动起点x坐标。 | 1722| from_y | 是 | 滑动起点y坐标。 | 1723| to_x | 是 | 滑动终点x坐标。 | 1724| to_y | 是 | 滑动终点y坐标。 | 1725| swipeVelocityPps_ | 否 | 滑动速度,单位: (px/s),取值范围:200-40000。<br> 默认值: 600。 | 1726| stepLength_ | 否 | 滑动步长。默认值: 滑动距离/50。<br> **为实现更好的模拟效果,推荐参数缺省/使用默认值。** | 1727 1728 1729```shell 1730# 执行快滑操作,stepLength_缺省。 1731hdc shell uitest uiInput fling 10 10 200 200 500 1732``` 1733 1734##### uiInput swipe/drag使用示例 1735 1736| 配置参数 | 必填 | 描述 | 1737|------|------------------|-----------------| 1738| from_x | 是 | 滑动起点x坐标。 | 1739| from_y | 是 | 滑动起点y坐标。 | 1740| to_x | 是 | 滑动终点x坐标。 | 1741| to_y | 是 | 滑动终点y坐标。 | 1742| swipeVelocityPps_ | 否 | 滑动速度,单位: (px/s),取值范围:200-40000。<br> 默认值: 600。 | 1743 1744```shell 1745# 执行慢滑操作。 1746hdc shell uitest uiInput swipe 10 10 200 200 500 1747 1748# 执行拖拽操作。 1749hdc shell uitest uiInput drag 10 10 100 100 500 1750``` 1751 1752##### uiInput dircFling使用示例 1753 1754| 配置参数 | 必填 | 描述 | 1755|-------------------|-------------|----------| 1756| direction | 否 | 滑动方向,取值范围:[0,1,2,3],默认值为0。<br> 0代表向左滑动,1代表向右滑动,2代表向上滑动,3代表向下滑动。 | 1757| swipeVelocityPps_ | 否| 滑动速度,单位: (px/s),取值范围:200-40000。<br> 默认值: 600。 | 1758| stepLength | 否 | 滑动步长。<br> 默认值: 滑动距离/50。为更好的模拟效果,推荐参数缺省/使用默认值。 | 1759 1760```shell 1761# 执行左滑操作 1762hdc shell uitest uiInput dircFling 0 500 1763# 执行向右滑动操作 1764hdc shell uitest uiInput dircFling 1 600 1765# 执行向上滑动操作。 1766hdc shell uitest uiInput dircFling 2 1767# 执行向下滑动操作。 1768hdc shell uitest uiInput dircFling 3 1769``` 1770 1771##### uiInput inputText使用示例 1772 1773| 配置参数 | 必填 | 描述 | 1774|------|------------------|----------| 1775| point_x | 是 | 输入框x坐标点。 | 1776| point_y | 是 | 输入框y坐标点。 | 1777| text | 是 | 输入文本内容。 | 1778 1779```shell 1780# 执行输入框输入操作。 1781hdc shell uitest uiInput inputText 100 100 hello 1782``` 1783 1784##### uiInput text使用示例 1785| 配置参数 | 必填 | 描述 | 1786|------|------------------|----------| 1787| text | 是 | 输入文本内容。 | 1788 1789```shell 1790# 无需输入坐标点,在当前获焦处,执行输入框输入操作。若当前获焦处不支持文本输入,则无实际效果。 1791hdc shell uitest uiInput text hello 1792``` 1793 1794##### uiInput keyEvent使用示例 1795 1796| 配置参数 | 必填 | 描述 | 1797|------|------|----------| 1798| keyID1 | 是 | 实体按键对应ID,取值范围:KeyCode/Back/Home/Power。<br>当取Back/Home/Power时,不支持输入组合键。 | 1799| keyID2 | 否 | 实体按键对应ID。 | 1800| keyID3 | 否 | 实体按键对应ID。 | 1801 1802>**说明** 1803> 1804> 最多支持传入是三个键值,具体取值请参考[KeyCode](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-input-kit/js-apis-keycode.md)。 1805 1806```shell 1807# 执行执行返回主页操作。 1808hdc shell uitest uiInput keyEvent Home 1809# 执行返回操作。 1810hdc shell uitest uiInput keyEvent Back 1811# 执行组合键粘贴操作。 1812hdc shell uitest uiInput keyEvent 2072 2038 1813``` 1814 1815#### 获取版本信息 1816 1817```bash 1818hdc shell uitest --version 1819``` 1820#### 拉起uitest测试进程 1821 1822```shell 1823hdc shell uitest start-daemon 1824``` 1825 1826### UI测试框架自构建方式 1827 1828#### 构建命令 1829 1830```shell 1831./build.sh --product-name rk3568 --build-target uitestkit 1832``` 1833#### 推送位置 1834 1835```shell 1836hdc target mount 1837hdc shell mount -o rw,remount / 1838hdc file send uitest /system/bin/uitest 1839hdc file send libuitest.z.so /system/lib/module/libuitest.z.so 1840hdc shell chmod +x /system/bin/uitest 1841``` 1842 1843## 版本信息 1844 1845| 版本号 | 功能说明 | 1846| :------ | :----------------------------------------------------------- | 1847| 3.2.2.1 | 1、增加抛滑、获取/设置屏幕方向接口<br />2、窗口处理逻辑增加不支持场景处理逻辑 | 1848| 3.2.3.0 | 1、滑动控件进行滑动查找、滑动到尾部/顶部功能优化 | 1849| 3.2.4.0 | 1、接口调用异常时会抛出错误码 | 1850| 3.2.5.0 | 1、通信机制变更 | 1851| 3.2.6.0 | 1、增加模拟鼠标操作能力接口<br />2、增加指定应用的窗口下查找目标控件接口 | 1852| 4.0.1.1 | 1、支持在daemon运行时执行uitest dumpLayout | 1853| 4.0.1.2 | 1、模拟鼠标动作、键鼠协同功能优化 | 1854| 4.0.1.3 | 1、示例代码更新<br />2、滑动控件进行滑动查找、滑动到尾部/顶部功能优化 | 1855| 4.0.1.4 | 1、可选参数传入undefined时,当作默认值处理 | 1856| 4.0.2.0 | 1、支持监听toast和dialog控件出现,使用callback的形式返回结果。 | 1857| 4.0.3.0 | 1、增加加载运行.abc文件机制。 | 1858| 4.0.4.0 | 1、支持abc_loader框架获取UI操作录制数据,屏幕数据,控件树等,并以callback的形式返回结果<br />2、修改录制数据结构 | 1859| 4.1.1.1 | 1、对接批量获取控件信息能力,缩短获取控件信息的耗时。 | 1860| 4.1.2.0 | 1、增加shell命令方式注入UI模拟操作。 | 1861| 4.1.3.0 | 1、新增命令行功能,uitest dumuLayout -a ,dump信息中包含控件的背景色、字体颜色/大小信息。 | 1862| 4.1.4.0 | 1、dump信息中增加hint与description字段。<br />2、优化多指操作。<br />3、优化查找控件的效率。<br />4、uitest uiInput执行效率提升。 | 1863| 5.0.1.0 | 1、优化swipe操作。<br />2、inputText输入中文的实现方式改为设置剪贴板数据后,长按控件点击粘贴。 | 1864| 5.0.1.1 | 1、节点新增以下属性,背景色:backgroundColor,背景图片:backgroundImage,透明度:opacity,模糊度:blur,事件是否透传:hitTestBehavior 。 | 1865| 5.0.1.2 | 1、通过test Sa发布公共事件。<br />2、节点新增clip属性,判断其子节点是否进行切割。<br />3、过滤机制调整,节点只与其clip为true的父节点进行切换计算可见区域,可见区域宽/高小于等于0记为不可见。<br />4、调用inputText时,被输入字符串超过200个字符时,实现方式调整为设置剪贴板数据后,植入ctrl + v。 | 1866| 5.1.1.1 | 1、控件支持正则表达式方式进行查找 <br />2、获取控件属性中的提示文本信息 <br />3、支持横向滑动查找操作 <br />4、支持不指定坐标模拟输入文本的shell命令 hdc shell uitest uiInput text "xxxx" | 1867| 5.1.1.2 | uitest dumpLayout 能力增强<br /> -w:仅获取指定window id的应用窗口。<br/> -b :仅获取指定bundleName的应用窗口。<br/> -m :是否进行窗口合并。不使用该选项时默认进行窗口合并。 | 1868