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 29### 使用说明 30 31#### 基础流程 32 33测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。 34 35| No. | API | 功能说明 | 36| ---- | ---------- | ------------------------------------------------------------ | 37| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数。 | 38| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数。 | 39| 3 | beforeEach | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数。 | 40| 4 | afterEach | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数。 | 41| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数。 | 42| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数。 | 43| 7 | expect | 支持bool类型判断等多种断言方法。 | 44 45示例代码: 46 47```javascript 48import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' 49import demo from '@ohos.bundle' 50 51export default async function abilityTest() { 52 describe('ActsAbilityTest', function () { 53 it('String_assertContain_success', 0, function () { 54 let a = 'abc' 55 let b = 'b' 56 expect(a).assertContain(b) 57 expect(a).assertEqual(a) 58 }) 59 it('getBundleInfo_0100', 0, async function () { 60 const NAME1 = "com.example.MyApplicationStage" 61 await demo.getBundleInfo(NAME1, 62 demo.BundleFlag.GET_BUNDLE_WITH_ABILITIES | demo.BundleFlag.GET_BUNDLE_WITH_REQUESTED_PERMISSION) 63 .then((value) => { 64 console.info(value.appId) 65 }) 66 .catch((err) => { 67 console.info(err.code) 68 }) 69 }) 70 }) 71} 72``` 73 74 75 76#### 断言库 77 78断言功能列表: 79 80 81| No. | API | 功能说明 | 82| :--- | :------------------| ------------------------------------------------------------ | 83| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1)。 | 84| 2 | assertContain | 检验actualvalue中是否包含expectvalue。 | 85| 3 | assertEqual | 检验actualvalue是否等于expectvalue[0]。 | 86| 4 | assertFail | 抛出一个错误。 | 87| 5 | assertFalse | 检验actualvalue是否是false。 | 88| 6 | assertTrue | 检验actualvalue是否是true。 | 89| 7 | assertInstanceOf | 检验actualvalue是否是expectvalue类型。 | 90| 8 | assertLarger | 检验actualvalue是否大于expectvalue。 | 91| 9 | assertLess | 检验actualvalue是否小于expectvalue。 | 92| 10 | assertNull | 检验actualvalue是否是null。 | 93| 11 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue。 | 94| 12 | assertUndefined | 检验actualvalue是否是undefined。 | 95| 13 | assertNaN | 检验actualvalue是否是一个NAN | 96| 14 | assertNegUnlimited | 检验actualvalue是否等于Number.NEGATIVE_INFINITY | 97| 15 | assertPosUnlimited | 检验actualvalue是否等于Number.POSITIVE_INFINITY | 98| 16 | assertDeepEquals | 检验actualvalue和expectvalue是否完全相等 | 99| 17 | assertPromiseIsPending | 判断promise是否处于Pending状态。 | 100| 18 | assertPromiseIsRejected | 判断promise是否处于Rejected状态。 | 101| 19 | assertPromiseIsRejectedWith | 判断promise是否处于Rejected状态,并且比较执行的结果值。| 102| 20 | assertPromiseIsRejectedWithError | 判断promise是否处于Rejected状态并有异常,同时比较异常的类型和message值。 | 103| 21 | assertPromiseIsResolved | 判断promise是否处于Resolved状态。 | 104| 22 | assertPromiseIsResolvedWith | 判断promise是否处于Resolved状态,并且比较执行的结果值。| 105| 23 | not | 断言取反,支持上面所有的断言功能 | 106 107示例代码: 108 109```javascript 110import { describe, it, expect } from '@ohos/hypium' 111export default async function abilityTest() { 112 describe('assertClose', function () { 113 it('assertBeClose success', 0, function () { 114 let a = 100 115 let b = 0.1 116 expect(a).assertClose(99, b) 117 }) 118 it('assertBeClose fail', 0, function () { 119 let a = 100 120 let b = 0.1 121 expect(a).assertClose(1, b) 122 }) 123 it('assertBeClose fail', 0, function () { 124 let a = 100 125 let b = 0.1 126 expect(a).assertClose(null, b) 127 }) 128 it('assertBeClose fail', 0, function () { 129 expect(null).assertClose(null, 0) 130 }) 131 it('assertNaN success',0, function () { 132 expect(Number.NaN).assertNaN(); // true 133 }) 134 it('assertNegUnlimited success',0, function () { 135 expect(Number.NEGATIVE_INFINITY).assertNegUnlimited(); // true 136 }) 137 it('assertPosUnlimited success',0, function () { 138 expect(Number.POSITIVE_INFINITY).assertPosUnlimited(); // true 139 }) 140 it('not_number_true',0, function () { 141 expect(1).not().assertLargerOrEqual(2) 142 }) 143 it('not_number_true_1',0, function () { 144 expect(3).not().assertLessOrEqual(2); 145 }) 146 it('not_NaN_true',0, function () { 147 expect(3).not().assertNaN(); 148 }) 149 it('not_contain_true',0, function () { 150 let a = "abc"; 151 let b= "cdf" 152 expect(a).not().assertContain(b); 153 }) 154 it('not_large_true',0, function () { 155 expect(3).not().assertLarger(4); 156 }) 157 it('not_less_true',0, function () { 158 expect(3).not().assertLess(2); 159 }) 160 it('not_undefined_true',0, function () { 161 expect(3).not().assertUndefined(); 162 }) 163 it('deepEquals_null_true',0, function () { 164 // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 165 expect(null).assertDeepEquals(null) 166 }) 167 it('deepEquals_array_not_have_true',0, function () { 168 // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 169 const a= [] 170 const b= [] 171 expect(a).assertDeepEquals(b) 172 }) 173 it('deepEquals_map_equal_length_success',0, function () { 174 // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 175 const a = new Map(); 176 const b = new Map(); 177 a.set(1,100); 178 a.set(2,200); 179 b.set(1, 100); 180 b.set(2, 200); 181 expect(a).assertDeepEquals(b) 182 }) 183 it("deepEquals_obj_success_1", 0, function () { 184 const a = {x:1}; 185 const b = {x:1}; 186 expect(a).assertDeepEquals(b); 187 }) 188 it("deepEquals_regExp_success_0", 0, function () { 189 const a = new RegExp("/test/"); 190 const b = new RegExp("/test/"); 191 expect(a).assertDeepEquals(b) 192 }) 193 it('test_isPending_pass_1', 0, function () { 194 let p = new Promise(function () { 195 }); 196 expect(p).assertPromiseIsPending(); 197 }); 198 it('test_isRejected_pass_1', 0, function () { 199 let p = Promise.reject({ 200 bad: 'no' 201 }); 202 expect(p).assertPromiseIsRejected(); 203 }); 204 it('test_isRejectedWith_pass_1', 0, function () { 205 let p = Promise.reject({ 206 res: 'reject value' 207 }); 208 expect(p).assertPromiseIsRejectedWith({ 209 res: 'reject value' 210 }); 211 }); 212 it('test_isRejectedWithError_pass_1', 0, function () { 213 let p1 = Promise.reject(new TypeError('number')); 214 expect(p1).assertPromiseIsRejectedWithError(TypeError); 215 }); 216 it('test_isResolved_pass_1', 0, function () { 217 let p = Promise.resolve({ 218 res: 'result value' 219 }); 220 expect(p).assertPromiseIsResolved(); 221 }); 222 it('test_isResolvedTo_pass_1', 0, function () { 223 let p = Promise.resolve({ 224 res: 'result value' 225 }); 226 expect(p).assertPromiseIsResolvedWith({ 227 res: 'result value' 228 }); 229 }); 230 it('test_isPending_failed_1', 0, function () { 231 let p = Promise.reject({ 232 bad: 'no1' 233 }); 234 expect(p).assertPromiseIsPending(); 235 }); 236 it('test_isRejectedWithError_failed_1', 0, function () { 237 let p = Promise.reject(new TypeError('number')); 238 expect(p).assertPromiseIsRejectedWithError(TypeError, 'number one'); 239 }); 240 }) 241} 242``` 243 244 245#### Mock能力 246 247##### 约束限制 248 249单元测试框架Mock能力从npm包[1.0.1版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium)开始支持,需修改源码工程中package.info中配置依赖npm包版本号后使用。 250 251- **接口列表:** 252 253| No. | API | 功能说明 | 254| --- | --- | --- | 255| 1 | mockFunc(obj: object, f:function()) | mock某个类的对象obj的函数f,那么需要传两个参数:obj和f,支持使用异步函数(说明:对mock而言原函数实现是同步或异步没太多区别,因为mock并不关注原函数的实现)。 | 256| 2 | when(mockedfunc:function) | 对传入后方法做检查,检查是否被mock并标记过,返回的是一个方法声明。 | 257| 3 | afterReturn(x:value) | 设定预期返回一个自定义的值value,比如某个字符串或者一个promise。 | 258| 4 | afterReturnNothing() | 设定预期没有返回值,即 undefined。 | 259| 5 | afterAction(x:action) | 设定预期返回一个函数执行的操作。 | 260| 6 | afterThrow(x:msg) | 设定预期抛出异常,并指定异常msg。 | 261| 7 | clear() | 用例执行完毕后,进行数据mocker对象的还原处理(还原之后对象恢复被mock之前的功能)。 | 262| 8 | any | 设定用户传任何类型参数(undefined和null除外),执行的结果都是预期的值,使用ArgumentMatchers.any方式调用。 | 263| 9 | anyString | 设定用户传任何字符串参数,执行的结果都是预期的值,使用ArgumentMatchers.anyString方式调用。 | 264| 10 | anyBoolean | 设定用户传任何boolean类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyBoolean方式调用。 | 265| 11 | anyFunction | 设定用户传任何function类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyFunction方式调用。 | 266| 12 | anyNumber | 设定用户传任何数字类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyNumber方式调用。 | 267| 13 | anyObj | 设定用户传任何对象类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyObj方式调用。 | 268| 14 | matchRegexs(Regex) | 设定用户传任何正则表达式类型参数Regex,执行的结果都是预期的值,使用ArgumentMatchers.matchRegexs(Regex)方式调用。 | 269| 15 | verify(methodName, argsArray) | 验证methodName(函数名字符串)所对应的函数和其参数列表argsArray的执行行为是否符合预期,返回一个VerificationMode:一个提供验证模式的类,它有times(count)、once()、atLeast(x)、atMost(x)、never()等函数可供选择。 | 270| 16 | times(count) | 验证行为调用过count次。 | 271| 17 | once() | 验证行为调用过一次。 | 272| 18 | atLeast(count) | 验证行为至少调用过count次。 | 273| 19 | atMost(count) | 验证行为至多调用过count次。 | 274| 20 | never | 验证行为从未发生过。 | 275| 21 | ignoreMock(obj, method) | 使用ignoreMock可以还原obj对象中被mock后的函数,对被mock后的函数有效。 | 276| 22 | clearAll() | 用例执行完毕后,进行数据和内存清理。 | 277 278- **使用示例:** 279 280用户可以通过以下方式进行引入mock模块进行测试用例编写: 281 282- **须知:** 283使用时候必须引入的mock能力模块: MockKit,when 284根据自己用例需要引入断言能力api 285例如:`import { describe, expect, it, MockKit, when} from '@ohos/hypium'` 286 287**示例1:afterReturn 的使用** 288 289```javascript 290import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 291 292export default function ActsAbilityTest() { 293 describe('ActsAbilityTest', function () { 294 it('testMockfunc', 0, function () { 295 console.info("it1 begin"); 296 297 //1.创建一个mock能力的对象MockKit 298 let mocker = new MockKit(); 299 300 //2.定类ClassName,里面两个函数,然后创建一个对象claser 301 class ClassName { 302 constructor() { 303 } 304 305 method_1(arg) { 306 return '888888'; 307 } 308 309 method_2(arg) { 310 return '999999'; 311 } 312 } 313 314 let claser = new ClassName(); 315 316 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 317 let mockfunc = mocker.mockFunc(claser, claser.method_1); 318 when(mockfunc)('test').afterReturn('1'); 319 320 //4.对mock后的函数进行断言,看是否符合预期 321 //执行成功案例,参数为'test' 322 expect(claser.method_1('test')).assertEqual('1'); //执行通过 323 324 //执行失败案例,参数为 'abc' 325 //expect(claser.method_1('abc')).assertEqual('1');//执行失败 326 }); 327 }); 328} 329``` 330- **须知:** 331`when(mockfunc)('test').afterReturn('1');` 332这句代码中的`('test')`是mock后的函数需要传递的匹配参数,目前支持一个参数 333`afterReturn('1')`是用户需要预期返回的结果。 334有且只有在参数是`('test')`的时候,执行的结果才是用户自定义的预期结果。 335 336**示例2: afterReturnNothing 的使用** 337 338```javascript 339import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 340 341export default function ActsAbilityTest() { 342 describe('ActsAbilityTest', function () { 343 it('testMockfunc', 0, function () { 344 console.info("it1 begin"); 345 346 //1.创建一个mock能力的对象MockKit 347 let mocker = new MockKit(); 348 349 //2.定类ClassName,里面两个函数,然后创建一个对象claser 350 class ClassName { 351 constructor() { 352 } 353 354 method_1(arg) { 355 return '888888'; 356 } 357 358 method_2(arg) { 359 return '999999'; 360 } 361 } 362 363 let claser = new ClassName(); 364 365 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 366 let mockfunc = mocker.mockFunc(claser, claser.method_1); 367 368 //4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterReturnNothing();即不返回任何值 369 when(mockfunc)('test').afterReturnNothing(); 370 371 //5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 372 //执行成功案例,参数为'test',这时候执行原对象claser.method_1的方法,会发生变化 373 // 这时候执行的claser.method_1不会再返回'888888',而是设定的afterReturnNothing()生效//不返回任何值; 374 expect(claser.method_1('test')).assertUndefined(); //执行通过 375 376 // 执行失败案例,参数传为 123 377 // expect(method_1(123)).assertUndefined();//执行失败 378 }); 379 }); 380} 381``` 382 383**示例3: 设定参数类型为any ,即接受任何参数(undefine和null除外)的使用** 384 385 386- **须知:** 387需要引入ArgumentMatchers类,即参数匹配器,例如:ArgumentMatchers.any 388 389```javascript 390import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 391 392export default function ActsAbilityTest() { 393 describe('ActsAbilityTest', function () { 394 it('testMockfunc', 0, function () { 395 console.info("it1 begin"); 396 397 //1.创建一个mock能力的对象MockKit 398 let mocker = new MockKit(); 399 400 //2.定类ClassName,里面两个函数,然后创建一个对象claser 401 class ClassName { 402 constructor() { 403 } 404 405 method_1(arg) { 406 return '888888'; 407 } 408 409 method_2(arg) { 410 return '999999'; 411 } 412 } 413 414 let claser = new ClassName(); 415 416 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 417 let mockfunc = mocker.mockFunc(claser, claser.method_1); 418 //根据自己需求进行选择参数匹配器和预期方法, 419 when(mockfunc)(ArgumentMatchers.any).afterReturn('1'); 420 421 //4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 422 //执行成功的案例1,传参为字符串类型 423 expect(claser.method_1('test')).assertEqual('1'); //用例执行通过。 424 //执行成功的案例2,传参为数字类型123 425 expect(claser.method_1(123)).assertEqual('1');//用例执行通过。 426 //执行成功的案例3,传参为boolean类型true 427 expect(claser.method_1(true)).assertEqual('1');//用例执行通过。 428 429 //执行失败的案例,传参为数字类型空 430 //expect(claser.method_1()).assertEqual('1');//用例执行失败。 431 }); 432 }); 433} 434``` 435 436**示例4: 设定参数类型为anyString,anyBoolean等的使用** 437 438```javascript 439import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 440 441export default function ActsAbilityTest() { 442 describe('ActsAbilityTest', function () { 443 it('testMockfunc', 0, function () { 444 console.info("it1 begin"); 445 446 //1.创建一个mock能力的对象MockKit 447 let mocker = new MockKit(); 448 449 //2.定类ClassName,里面两个函数,然后创建一个对象claser 450 class ClassName { 451 constructor() { 452 } 453 454 method_1(arg) { 455 return '888888'; 456 } 457 458 method_2(arg) { 459 return '999999'; 460 } 461 } 462 463 let claser = new ClassName(); 464 465 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 466 let mockfunc = mocker.mockFunc(claser, claser.method_1); 467 //根据自己需求进行选择 468 when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1'); 469 470 //4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 471 //执行成功的案例,传参为字符串类型 472 expect(claser.method_1('test')).assertEqual('1'); //用例执行通过。 473 expect(claser.method_1('abc')).assertEqual('1'); //用例执行通过。 474 475 //执行失败的案例,传参为数字类型 476 //expect(claser.method_1(123)).assertEqual('1');//用例执行失败。 477 //expect(claser.method_1(true)).assertEqual('1');//用例执行失败。 478 }); 479 }); 480} 481``` 482 483**示例5: 设定参数类型为matchRegexs(Regex)等 的使用** 484```javascript 485import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 486 487export default function ActsAbilityTest() { 488 describe('ActsAbilityTest', function () { 489 it('testMockfunc', 0, function () { 490 console.info("it1 begin"); 491 492 //1.创建一个mock能力的对象MockKit 493 let mocker = new MockKit(); 494 495 //2.定类ClassName,里面两个函数,然后创建一个对象claser 496 class ClassName { 497 constructor() { 498 } 499 500 method_1(arg) { 501 return '888888'; 502 } 503 504 method_2(arg) { 505 return '999999'; 506 } 507 } 508 509 let claser = new ClassName(); 510 511 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 512 let mockfunc = mocker.mockFunc(claser, claser.method_1); 513 //根据自己需求进行选择,这里假设匹配正则,且正则为/123456/ 514 when(mockfunc)(ArgumentMatchers.matchRegexs(/123456/)).afterReturn('1'); 515 516 //4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法 517 //执行成功的案例,传参为字符串 比如 '1234567898' 518 expect(claser.method_1('1234567898')).assertEqual('1'); //用例执行通过。 519 //因为字符串 '1234567898'可以和正则/123456/匹配上 520 521 //执行失败的案例,传参为字符串'1234' 522 //expect(claser.method_1('1234')).assertEqual('1');//用例执行失败。反之 523 }); 524 }); 525} 526``` 527 528**示例6: 验证功能 Verify函数的使用** 529```javascript 530import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 531 532export default function ActsAbilityTest() { 533 describe('ActsAbilityTest', function () { 534 it('testMockfunc', 0, function () { 535 console.info("it1 begin"); 536 537 //1.创建一个mock能力的对象MockKit 538 let mocker = new MockKit(); 539 540 //2.定类ClassName,里面两个函数,然后创建一个对象claser 541 class ClassName { 542 constructor() { 543 } 544 545 method_1(...arg) { 546 return '888888'; 547 } 548 549 method_2(...arg) { 550 return '999999'; 551 } 552 } 553 554 let claser = new ClassName(); 555 556 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 557 mocker.mockFunc(claser, claser.method_1); 558 mocker.mockFunc(claser, claser.method_2); 559 560 //4.方法调用如下 561 claser.method_1('abc', 'ppp'); 562 claser.method_1('abc'); 563 claser.method_1('xyz'); 564 claser.method_1(); 565 claser.method_1('abc', 'xxx', 'yyy'); 566 claser.method_1(); 567 claser.method_2('111'); 568 claser.method_2('111', '222'); 569 570 //5.现在对mock后的两个函数进行验证,验证调用情况 571 mocker.verify('method_1', []).atLeast(3); //结果为failed 572 //解释:验证函数'method_1',参数列表为空:[] 的函数,至少执行过3次, 573 //执行结果为failed,因为'method_1'且无参数 在4中只执行过2次 574 //mocker.verify('method_2',['111']).once();//执行success,原因同上 575 //mocker.verify('method_2',['111',,'222']).once();//执行success,原因同上 576 }); 577 }); 578} 579``` 580 581**示例7: ignoreMock(obj, method) 忽略函数的使用** 582```javascript 583import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 584 585export default function ActsAbilityTest() { 586 describe('ActsAbilityTest', function () { 587 it('testMockfunc', 0, function () { 588 console.info("it1 begin"); 589 590 //1.创建一个mock能力的对象MockKit 591 let mocker = new MockKit(); 592 593 //2.定类ClassName,里面两个函数,然后创建一个对象claser 594 class ClassName { 595 constructor() { 596 } 597 598 method_1(...arg) { 599 return '888888'; 600 } 601 602 method_2(...arg) { 603 return '999999'; 604 } 605 } 606 607 let claser = new ClassName(); 608 609 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 610 let func_1 = mocker.mockFunc(claser, claser.method_1); 611 let func_2 = mocker.mockFunc(claser, claser.method_2); 612 613 //4.对mock后的函数的行为进行修改 614 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 615 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 616 617 //5.方法调用如下 618 console.log(claser.method_1(123)); //执行结果是4,符合步骤4中的预期 619 console.log(claser.method_2(456)); //执行结果是5,符合步骤4中的预期 620 621 //6.现在对mock后的两个函数的其中一个函数method_1进行忽略处理(原理是就是还原) 622 mocker.ignoreMock(claser, claser.method_1); 623 //然后再去调用 claser.method_1函数,看执行结果 624 console.log(claser.method_1(123)); //执行结果是888888,发现这时结果跟步骤4中的预期不一样了,执行了claser.method_1没被mock之前的结果 625 //用断言测试 626 expect(claser.method_1(123)).assertEqual('4'); //结果为failed 符合ignoreMock预期 627 claser.method_2(456); //执行结果是5,因为method_2没有执行ignore忽略,所有也符合步骤4中的预期 628 }); 629 }); 630} 631``` 632 633**示例8: clear()函数的使用** 634 635```javascript 636import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 637 638export default function ActsAbilityTest() { 639 describe('ActsAbilityTest', function () { 640 it('testMockfunc', 0, function () { 641 console.info("it1 begin"); 642 643 //1.创建一个mock能力的对象MockKit 644 let mocker = new MockKit(); 645 646 //2.定类ClassName,里面两个函数,然后创建一个对象claser 647 class ClassName { 648 constructor() { 649 } 650 651 method_1(...arg) { 652 return '888888'; 653 } 654 655 method_2(...arg) { 656 return '999999'; 657 } 658 } 659 let claser = new ClassName(); 660 661 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock 662 let func_1 = mocker.mockFunc(claser, claser.method_1); 663 let func_2 = mocker.mockFunc(claser, claser.method_2); 664 665 //4.对mock后的函数的行为进行修改 666 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 667 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 668 669 //5.方法调用如下 670 //expect(claser.method_1(123)).assertEqual('4');//ok 符合预期 671 //expect(claser.method_2(456)).assertEqual('5');//ok 符合预期 672 673 //6.清除mock操作(原理是就是还原) 674 mocker.clear(claser); 675 //然后再去调用 claser.method_1函数,看执行结果 676 expect(claser.method_1(123)).assertEqual('4');//failed 符合预期 677 expect(claser.method_2(456)).assertEqual('5');//failed 符合预期 678 }); 679 }); 680} 681``` 682 683 684**示例9: afterThrow(msg) 函数的使用** 685 686```javascript 687import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 688 689export default function ActsAbilityTest() { 690 describe('ActsAbilityTest', function () { 691 it('testMockfunc', 0, function () { 692 console.info("it1 begin"); 693 694 //1.创建一个mock能力的对象MockKit 695 let mocker = new MockKit(); 696 697 //2.定类ClassName,里面两个函数,然后创建一个对象claser 698 class ClassName { 699 constructor() { 700 } 701 702 method_1(arg) { 703 return '888888'; 704 } 705 } 706 707 let claser = new ClassName(); 708 709 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 710 let mockfunc = mocker.mockFunc(claser, claser.method_1); 711 712 //4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterReturnNothing();即不返回任何值 713 when(mockfunc)('test').afterThrow('error xxx'); 714 715 //5.执行mock后的函数,捕捉异常并使用assertEqual对比msg否符合预期 716 try { 717 claser.method_1('test'); 718 } catch (e) { 719 expect(e).assertEqual('error xxx');//执行通过 720 } 721 }); 722 }); 723} 724``` 725 726**示例10: mock异步 函数的使用** 727 728```javascript 729import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 730 731export default function ActsAbilityTest() { 732 describe('ActsAbilityTest', function () { 733 it('testMockfunc', 0, function () { 734 console.info("it1 begin"); 735 736 //1.创建一个mock能力的对象MockKit 737 let mocker = new MockKit(); 738 739 //2.定类ClassName,里面两个函数,然后创建一个对象claser 740 class ClassName { 741 constructor() { 742 } 743 744 async method_1(arg) { 745 return new Promise((res, rej) => { 746 //做一些异步操作 747 setTimeout(function () { 748 console.log('执行'); 749 res('数据传递'); 750 }, 2000); 751 }); 752 } 753 } 754 755 let claser = new ClassName(); 756 757 //3.进行mock操作,比如需要对ClassName类的method_1函数进行mock 758 let mockfunc = mocker.mockFunc(claser, claser.method_1); 759 760 //4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterRetrun; 可以自定义返回一个promise 761 when(mockfunc)('test').afterReturn(new Promise((res, rej) => { 762 console.log("do something"); 763 res('success something'); 764 })); 765 766 //5.执行mock后的函数,即对定义的promise进行后续执行 767 claser.method_1('test').then(function (data) { 768 //数据处理代码... 769 console.log('result : ' + data); 770 }); 771 }); 772 }); 773} 774``` 775 776**示例11:mock 系统函数的使用** 777 778```javascript 779export default function ActsAbilityTest() { 780 describe('ActsAbilityTest', function () { 781 it('test_systemApi', 0, function () { 782 //1.创建MockKit对象 783 let mocker = new MockKit(); 784 //2.mock app.getInfo函数 785 let mockf = mocker.mockFunc(app, app.getInfo); 786 when(mockf)('test').afterReturn('1'); 787 //执行成功案例 788 expect(app.getInfo('test')).assertEqual('1'); 789 }); 790 }); 791} 792``` 793 794 795**示例12:verify times函数的使用(验证函数调用次数)** 796 797```javascript 798import { describe, expect, it, MockKit, when } from '@ohos/hypium' 799 800export default function ActsAbilityTest() { 801 describe('ActsAbilityTest', function () { 802 it('test_verify_times', 0, function () { 803 //1.创建MockKit对象 804 let mocker = new MockKit(); 805 //2.定义需要被mock的类 806 class ClassName { 807 constructor() { 808 } 809 810 method_1(...arg) { 811 return '888888'; 812 } 813 } 814 //3.创建类对象 815 let claser = new ClassName(); 816 //4.mock 类ClassName对象的某个方法,比如method_1 817 let func_1 = mocker.mockFunc(claser, claser.method_1); 818 //5.期望被mock后的函数能够返回自己假设的结果 819 when(func_1)('123').afterReturn('4'); 820 821 //6.随机执行几次函数,参数如下 822 claser.method_1('123', 'ppp'); 823 claser.method_1('abc'); 824 claser.method_1('xyz'); 825 claser.method_1(); 826 claser.method_1('abc', 'xxx', 'yyy'); 827 claser.method_1('abc'); 828 claser.method_1(); 829 //7.验证函数method_1且参数为'abc'时,执行过的次数是否为2 830 mocker.verify('method_1', ['abc']).times(2); 831 }); 832 }); 833} 834``` 835 836 837**示例13: verify atLeast 函数的使用 (验证函数调用次数)** 838 839```javascript 840import { describe, expect, it, MockKit, when } from '@ohos/hypium' 841 842export default function ActsAbilityTest() { 843 describe('ActsAbilityTest', function () { 844 it('test_verify_atLeast', 0, function () { 845 //1.创建MockKit对象 846 let mocker = new MockKit(); 847 //2.定义需要被mock的类 848 class ClassName { 849 constructor() { 850 } 851 852 method_1(...arg) { 853 return '888888'; 854 } 855 } 856 857 //3.创建类对象 858 let claser = new ClassName(); 859 //4.mock 类ClassName对象的某个方法,比如method_1 860 let func_1 = mocker.mockFunc(claser, claser.method_1); 861 //5.期望被mock后的函数能够返回自己假设的结果 862 when(func_1)('123').afterReturn('4'); 863 //6.随机执行几次函数,参数如下 864 claser.method_1('123', 'ppp'); 865 claser.method_1('abc'); 866 claser.method_1('xyz'); 867 claser.method_1(); 868 claser.method_1('abc', 'xxx', 'yyy'); 869 claser.method_1(); 870 //7.验证函数method_1且参数为空时,是否至少执行过2次 871 mocker.verify('method_1', []).atLeast(2); 872 }); 873 }); 874} 875``` 876 877#### 数据驱动 878 879##### 约束限制 880 881单元测试框架数据驱动能力从[hypium 1.0.2版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium)开始支持。 882 883- 数据参数传递 : 为指定测试套、测试用例传递测试输入数据参数。 884- 压力测试 : 为指定测试套、测试用例设置执行次数。 885 886数据驱动可以根据配置参数来驱动测试用例的执行次数和每一次传入的参数,使用时依赖data.json配置文件,文件内容如下: 887 888>说明 : data.json与测试用例*.test.js|ets文件同目录 889 890```json 891{ 892 "suites": [{ 893 "describe": ["actsAbilityTest"], 894 "stress": 2, 895 "params": { 896 "suiteParams1": "suiteParams001", 897 "suiteParams2": "suiteParams002" 898 }, 899 "items": [{ 900 "it": "testDataDriverAsync", 901 "stress": 2, 902 "params": [{ 903 "name": "tom", 904 "value": 5 905 }, { 906 "name": "jerry", 907 "value": 4 908 }] 909 }, { 910 "it": "testDataDriver", 911 "stress": 3 912 }] 913 }] 914} 915``` 916 917配置参数说明: 918 919| | 配置项名称 | 功能 | 必填 | 920| :--- | :--------- | :------------------------------------ | ---- | 921| 1 | "suite" | 测试套配置 。 | 是 | 922| 2 | "items" | 测试用例配置 。 | 是 | 923| 3 | "describe" | 测试套名称 。 | 是 | 924| 4 | "it" | 测试用例名称 。 | 是 | 925| 5 | "params" | 测试套 / 测试用例 可传入使用的参数 。 | 否 | 926| 6 | "stress" | 测试套 / 测试用例 指定执行次数 。 | 否 | 927 928示例代码: 929 930在TestAbility目录下app.js|ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据 931 932```javascript 933import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' 934import { Hypium } from '@ohos/hypium' 935import testsuite from '../test/List.test' 936import data from '../test/data.json'; 937 938... 939Hypium.setData(data); 940Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) 941... 942``` 943 944```javascript 945import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium'; 946 947export default function abilityTest() { 948 describe('actsAbilityTest', function () { 949 it('testDataDriverAsync', 0, async function (done, data) { 950 console.info('name: ' + data.name); 951 console.info('value: ' + data.value); 952 done(); 953 }); 954 955 it('testDataDriver', 0, function () { 956 console.info('stress test'); 957 }); 958 }); 959} 960``` 961 962### 使用方式 963 964单元测试框架以npm包(hypium)形式发布至[服务组件官网](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium),开发者可以下载Deveco Studio后,在应用工程中配置依赖后使用框架能力,测试工程创建及测试脚本执行使用指南请参见[IDE指导文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568)。 965 966## Ui测试框架功能特性 967 968| No. | 特性 | 功能说明 | 969| ---- | ----------- | ------------------------------------------------------------ | 970| 1 | UiDriver | Ui测试的入口,提供查找控件,检查控件存在性以及注入按键能力。 | 971| 2 | By | 用于描述目标控件特征(文本、id、类型等),`UiDriver`根据`By`描述的控件特征信息来查找控件。 | 972| 3 | UiComponent | UiDriver查找返回的控件对象,提供查询控件属性,滑动查找等触控和检视能力。 | 973| 4 | UiWindow | UiDriver查找返回的窗口对象,提供获取窗口属性、操作窗口的能力。 | 974 975**使用者在测试脚本通过如下方式引入使用:** 976 977```typescript 978import {UiDriver,BY,UiComponent,Uiwindow,MatchPattern} from '@ohos.uitest' 979``` 980 981> 须知 982> 1. `By`类提供的接口全部是同步接口,使用者可以使用`builder`模式链式调用其接口构造控件筛选条件。 983> 2. `UiDriver`和`UiComponent`类提供的接口全部是异步接口(`Promise`形式),**需使用`await`语法**。 984> 3. Ui测试用例均需使用**异步**语法编写用例,需遵循单元测试框架异步用例编写规范。 985 986 987 988在测试用例文件中import `By/UiDriver/UiComponent`类,然后调用API接口编写测试用例。 989 990```javascript 991import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium' 992import {BY, UiDriver, UiComponent, MatchPattern} from '@ohos.uitest' 993 994export default async function abilityTest() { 995 describe('uiTestDemo', function() { 996 it('uitest_demo0', 0, async function() { 997 // create UiDriver 998 let driver = await UiDriver.create() 999 // find component by text 1000 let button = await driver.findComponent(BY.text('hello').enabled(true)) 1001 // click component 1002 await button.click() 1003 // get and assert component text 1004 let content = await button.getText() 1005 expect(content).assertEquals('clicked!') 1006 }) 1007 }) 1008} 1009``` 1010 1011### UiDriver使用说明 1012 1013`UiDriver`类作为UiTest测试框架的总入口,提供查找控件,注入按键,单击坐标,滑动控件,手势操作,截图等能力。 1014 1015| No. | API | 功能描述 | 1016| ---- | ------------------------------------------------------------ | ------------------------ | 1017| 1 | create():Promise<UiDriver> | 静态方法,构造UiDriver。 | 1018| 2 | findComponent(b:By):Promise<UiComponent> | 查找匹配控件。 | 1019| 3 | pressBack():Promise<void> | 单击BACK键。 | 1020| 4 | click(x:number, y:number):Promise<void> | 基于坐标点的单击。 | 1021| 5 | swipe(x1:number, y1:number, x2:number, y2:number):Promise<void> | 基于坐标点的滑动。 | 1022| 6 | assertComponentExist(b:By):Promise<void> | 断言匹配的控件存在。 | 1023| 7 | delayMs(t:number):Promise<void> | 延时。 | 1024| 8 | screenCap(s:path):Promise<void> | 截屏。 | 1025| 9 | findWindow(filter: WindowFilter): Promise<UiWindow> | 查找匹配窗口。 | 1026 1027其中assertComponentExist接口是断言API,用于断言当前界面存在目标控件;如果控件不存在,该API将抛出JS异常,使当前测试用例失败。 1028 1029```javascript 1030import {BY,UiDriver,UiComponent} from '@ohos.uitest' 1031 1032export default async function abilityTest() { 1033 describe('UiTestDemo', function() { 1034 it('Uitest_demo0', 0, async function(done) { 1035 try{ 1036 // create UiDriver 1037 let driver = await UiDriver.create() 1038 // assert text 'hello' exists on current Ui 1039 await assertComponentExist(BY.text('hello')) 1040 } finally { 1041 done() 1042 } 1043 }) 1044 }) 1045} 1046``` 1047 1048`UiDriver`完整的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/js-apis-uitest.md#uidriver)。 1049 1050### By使用说明 1051 1052Ui测试框架通过`By`类提供了丰富的控件特征描述API,用来匹配查找要操作或检视的目标控件。`By`提供的API能力具有以下特点: 1053 1054- 支持匹配单属性和匹配多属性组合,例如同时指定目标控件text和id。 1055- 控件属性支持多种匹配模式(等于,包含,`STARTS_WITH`,`ENDS_WITH`)。 1056- 支持相对定位控件,可通过`isBefore`和`isAfter`等API限定邻近控件特征进行辅助定位。 1057 1058| No. | API | 功能描述 | 1059| ---- | ---------------------------------- | ------------------------------------------------ | 1060| 1 | id(i:number):By | 指定控件id。 | 1061| 2 | text(t:string, p?:MatchPattern):By | 指定控件文本,可指定匹配模式。 | 1062| 3 | type(t:string)):By | 指定控件类型。 | 1063| 4 | enabled(e:bool):By | 指定控件使能状态。 | 1064| 5 | clickable(c:bool):By | 指定控件可单击状态。 | 1065| 6 | focused(f:bool):By | 指定控件获焦状态。 | 1066| 7 | scrollable(s:bool):By | 指定控件可滑动状态。 | 1067| 8 | selected(s:bool):By | 指定控件选中状态。 | 1068| 9 | isBefore(b:By):By | **相对定位**,限定目标控件位于指定特征控件之前。 | 1069| 10 | isAfter(b:By):By | **相对定位**,限定目标控件位于指定特征控件之后。 | 1070 1071其中,`text`属性支持{`MatchPattern.EQUALS`,`MatchPattern.CONTAINS`,`MatchPattern.STARTS_WITH`,`MatchPattern.ENDS_WITH`}四种匹配模式,缺省使用`MatchPattern.EQUALS`模式。 1072 1073`By`完整的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/js-apis-uitest.md#by)。 1074 1075#### 控件绝对定位 1076 1077**示例代码1**:查找id是`Id_button`的控件。 1078 1079```javascript 1080let button = await driver.findComponent(BY.id(Id_button)) 1081``` 1082 1083 **示例代码2**:查找id是`Id_button`并且状态是`enabled`的控件,适用于无法通过单一属性定位的场景。 1084 1085```javascript 1086let button = await driver.findComponent(BY.id(Id_button).enabled(true)) 1087``` 1088 1089通过`By.id(x).enabled(y)`来指定目标控件的多个属性。 1090 1091**示例代码3**:查找文本中包含`hello`的控件,适用于不能完全确定控件属性取值的场景。 1092 1093```javascript 1094let txt = await driver.findComponent(BY.text("hello", MatchPattern.CONTAINS)) 1095``` 1096 1097通过向`By.text()`方法传入第二个参数`MatchPattern.CONTAINS`来指定文本匹配规则;默认规则是`MatchPattern.EQUALS`,即目标控件text属性必须严格等于给定值。 1098 1099#### 控件相对定位 1100 1101**示例代码1**:查找位于文本控件`Item3_3`后面的,id是`ResourceTable.Id_switch`的Switch控件。 1102 1103```javascript 1104let switch = await driver.findComponent(BY.id(Id_switch).isAfter(BY.text("Item3_3"))) 1105``` 1106 1107通过`By.isAfter`方法,指定位于目标控件前面的特征控件属性,通过该特征控件进行相对定位。一般地,特征控件是某个具有全局唯一特征的控件(例如具有唯一的id或者唯一的text)。 1108 1109类似的,可以使用`By.isBefore`控件指定位于目标控件后面的特征控件属性,实现相对定位。 1110 1111### UiComponent使用说明 1112 1113`UiComponent`类代表了Ui界面上的一个控件,一般是通过`UiDriver.findComponent(by)`方法查找到的。通过该类的实例,用户可以获取控件属性,单击控件,滑动查找,注入文本等操作。 1114 1115`UiComponent`包含的常用API: 1116 1117| No. | API | 功能描述 | 1118| ---- | --------------------------------- | ---------------------------------------------- | 1119| 1 | click():Promise<void> | 单击该控件。 | 1120| 2 | inputText(t:string):Promise<void> | 向控件中输入文本(适用于文本框控件)。 | 1121| 3 | scrollSearch(s:By):Promise<bool> | 在该控件上滑动查找目标控件(适用于List等控件)。 | 1122| 4 | getText():Promise<string> | 获取控件text。 | 1123| 5 | getId():Promise<number> | 获取控件id。 | 1124| 6 | getType():Promise<string> | 获取控件类型。 | 1125| 7 | isEnabled():Promise<bool> | 获取控件使能状态。 | 1126 1127`UiComponent`完整的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/js-apis-uitest.md#uicomponent)。 1128 1129**示例代码1**:单击控件。 1130 1131```javascript 1132let button = await driver.findComponent(BY.id(Id_button)) 1133await button.click() 1134``` 1135 1136**示例代码2**:通过get接口获取控件属性后,可以使用单元测试框架提供的assert*接口做断言检查。 1137 1138```javascript 1139let component = await driver.findComponent(BY.id(Id_title)) 1140expect(component !== null).assertTrue() 1141``` 1142 1143**示例代码3**:在List控件中滑动查找text是`Item3_3`的子控件。 1144 1145```javascript 1146let list = await driver.findComponent(BY.id(Id_list)) 1147let found = await list.scrollSearch(BY.text("Item3_3")) 1148expect(found).assertTrue() 1149``` 1150 1151**示例代码4**:向输入框控件中输入文本。 1152 1153```javascript 1154let editText = await driver.findComponent(BY.type('InputText')) 1155await editText.inputText("user_name") 1156``` 1157### UiWindow使用说明 1158 1159`UiWindow`类代表了Ui界面上的一个窗口,一般是通过`UiDriver.findWindow(by)`方法查找到的。通过该类的实例,用户可以获取窗口属性,并进行窗口拖动、调整窗口大小等操作。 1160 1161`UiWindow`包含的常用API: 1162 1163| No. | API | 功能描述 | 1164| ---- | ------------------------------------------------------------ | -------------------------------------------------- | 1165| 1 | getBundleName(): Promise<string> | 获取窗口所属应用包名。 | 1166| 2 | getTitle(): Promise<string> | 获取窗口标题信息。 | 1167| 3 | focus(): Promise<bool> | 使得当前窗口获取焦点。 | 1168| 4 | moveTo(x: number, y: number): Promise<bool>; | 将当前窗口移动到指定位置(适用于支持移动的窗口)。 | 1169| 5 | resize(wide: number, height: number, direction: ResizeDirection): Promise<bool> | 调整窗口大小(适用于支持调整大小的窗口)。 | 1170| 6 | split(): Promise<bool> | 将窗口模式切换为分屏模式(适用于支持分屏的窗口)。 | 1171| 7 | close(): Promise<bool> | 关闭当前窗口。 | 1172 1173`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/js-apis-uitest.md#uiwindow9)。 1174 1175**示例代码1**:获取窗口属性。 1176 1177```javascript 1178let window = await driver.findWindow({actived: true}) 1179let bundelName = await window.getBundleName() 1180``` 1181 1182**示例代码2**:移动窗口。 1183 1184```javascript 1185let window = await driver.findWindow({actived: true}) 1186await window.moveTo(500,500) 1187``` 1188 1189**示例代码3**:关闭窗口。 1190 1191```javascript 1192let window = await driver.findWindow({actived: true}) 1193await window.close() 1194``` 1195 1196### 使用方式 1197 1198 开发者可以下载Deveco Studio创建测试工程后,在其中调用框架提供接口进行相关测试操作,测试工程创建及测试脚本执行使用指南请参见[IDE指导文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568)。 1199 UI测试框架使能需要执行如下命令。 1200 1201>```shell 1202> hdc_std shell param set persist.ace.testmode.enabled 1 1203>``` 1204### UI测试框架自构建方式 1205 1206> Ui测试框架在OpenHarmony-3.1-Release版本中未随版本编译,需手动处理,请参考[3.1-Release版本使用指导](https://gitee.com/openharmony/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)。 1207 1208开发者如需自行编译Ui测试框架代码验证子修改内容,构建命令和推送位置请参考本章节内容。 1209 1210#### 构建命令 1211 1212```shell 1213./build.sh --product-name rk3568 --build-target uitestkit 1214``` 1215#### 推送位置 1216 1217```shell 1218hdc_std target mount 1219hdc_std shell mount -o rw,remount / 1220hdc_std file send uitest /system/bin/uitest 1221hdc_std file send libuitest.z.so /system/lib/module/libuitest.z.so 1222hdc_std shell chmod +x /system/bin/uitest 1223``` 1224 1225### 版本信息 1226 1227| 版本号 | 功能说明 | 1228| :------ | :----------------------------------------------------------- | 1229| 3.2.2.1 | 1、增加抛滑、获取/设置屏幕方向接口<br />2、窗口处理逻辑增加不支持场景处理逻辑 | 1230