14 Star 40 Fork 158

OpenHarmony / testfwk_arkxtest

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

自动化测试框架使用介绍

简介

OpenHarmony自动化测试框架代码部件仓arkXtest,包含单元测试框架(JsUnit)和Ui测试框架(UiTest)。

单元测试框架(JsUnit)提供单元测试用例执行能力,提供用例编写基础接口,生成对应报告,用于测试系统或应用接口。

Ui测试框架(UiTest)通过简洁易用的API提供查找和操作界面控件能力,支持用户开发基于界面操作的自动化测试脚本。

目录

arkXtest 
  |-----jsunit  单元测试框架
  |-----uitest  Ui测试框架

约束限制

本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。

单元测试框架功能特性

No. 特性 功能说明
1 基础流程 支持编写及异步执行基础用例。
2 断言库 判断用例实际期望值与预期值是否相符。
3 Mock能力 支持函数级mock能力,对定义的函数进行mock后修改函数的行为,使其返回指定的值或者执行某种动作。
4 数据驱动 提供数据驱动能力,支持复用同一个测试脚本,使用不同输入数据驱动执行。
5 专项能力 支持测试套与用例筛选、随机执行、压力测试、超时设置、遇错即停模式等。

使用说明

基础流程

测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。

No. API 功能说明
1 describe 定义一个测试套,支持两个参数:测试套名称和测试套函数。
2 beforeAll 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数。
3 beforeEach 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数。
4 afterEach 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数。
5 afterAll 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数。
6 beforeItSpecified 在测试套内定义一个单元预置条件,仅在指定测试用例开始前执行,支持两个参数:单个用例名称或用例名称数组、预置动作函数。
7 afterItSpecified 在测试套内定义一个单元清理条件,仅在指定测试用例结束后执行,支持两个参数:单个用例名称或用例名称数组、清理动作函数
8 it 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数。
9 expect 支持bool类型判断等多种断言方法。
10 getDescribeName 获取当前正在执行测试套的名称
11 getItName 获取当前正在执行测试用例的名称
12 getItAttribute 获取当前正在执行测试用例的级别、粒度、测试类型

示例代码:

 import { describe, it, expect, beforeItSpecified, afterItSpecified, SysTestKit, TestType, Size, Level} from '@ohos/hypium';
 import demo from '@ohos.bundle'
 import { BusinessError } from '@ohos.base';
 export default function abilityTest() {
  describe('ActsAbilityTest', () => {
    beforeItSpecified(['String_assertContain_success'], () => {
      const num:number = 1
      expect(num).assertEqual(1)
    })
    afterItSpecified(['String_assertContain_success'], async (done: Function) => {
      const str:string = 'abc'
      setTimeout(()=>{
        try {
          expect(str).assertContain('d')
        } catch (error) {
          console.error(`error message ${JSON.stringify(error)}`)
        }
        done()
      }, 1000)
    })
    it('getCurrentRunningSuiteName', 0, () => {
        let suiteName: string = SysTestKit.getDescribeName();
        expect(suiteName).assertEqual('ActsAbilityTest')
    })
    it('getCurrentRunningItInfo',TestType.SAFETY | Size.SMALLTEST, () => {
      let itName: string = SysTestKit.getItName();
      let itAttr: TestType | Size | Level = SysTestKit.getItAttribute()
      expect(itName).assertEqual('getCurrentRunningItInfo')
      expect(itAttr).assertEqual(TestType.SAFETY | Size.SMALLTEST)
    })
    it('String_assertContain_success', 0, () => {
      let a: string = 'abc'
      let b: string = 'b'
      expect(a).assertContain(b)
      expect(a).assertEqual(a)
    })
    it('getBundleInfo_0100', 0, async () => {
      const NAME1 = "com.example.myapplication0009921"
      await demo.getBundleInfo(NAME1,
        demo.BundleFlag.GET_BUNDLE_WITH_ABILITIES | demo.BundleFlag.GET_BUNDLE_WITH_REQUESTED_PERMISSION)
        .then((value: BundleInfo) => {
          console.info(value.appId)
        })
        .catch((err:BusinessError) => {
          console.info(err.code.toString())
        })
    })
  })
}

 interface BundleInfo {
   name: string;
   appId: string
 }

同时,@since1.0.6 测试套describe支持嵌套定义 。

约束限制:describe仅支持两层嵌套定义,且内层的describe-“innerDescribe”不支持“数据驱动”、“专项能力”特性。

示例代码:

import { describe, it, expect } from '@ohos/hypium';

export default async function nestedDescribeTest() {
  describe('outerDescribe', () => {
    describe('innerDescribe', () => {
      it('innerIt', 0, () =>{
        let a: string = 'abc'
        expect(a).assertEqual(a)
      })
    })
    it('outerIt', 0, () => {
      let a: string = 'abc'
      expect(a).assertEqual(a)
    })
  })
}

断言库

断言功能列表:

No. API 功能说明
1 assertClose 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1)。
2 assertContain 检验actualvalue中是否包含expectvalue。
3 assertEqual 检验actualvalue是否等于expectvalue[0]。
4 assertFail 抛出一个错误。
5 assertFalse 检验actualvalue是否是false。
6 assertTrue 检验actualvalue是否是true。
7 assertInstanceOf 检验actualvalue是否是expectvalue类型,支持基础类型。
8 assertLarger 检验actualvalue是否大于expectvalue。
9 assertLess 检验actualvalue是否小于expectvalue。
10 assertNull 检验actualvalue是否是null。
11 assertThrowError 检验actualvalue抛出Error内容是否是expectValue。
12 assertUndefined 检验actualvalue是否是undefined。
13 assertNaN @since1.0.4 检验actualvalue是否是一个NAN
14 assertNegUnlimited @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY
15 assertPosUnlimited @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY
16 assertDeepEquals @since1.0.4 检验actualvalue和expectvalue是否完全相等
17 assertPromiseIsPending @since1.0.4 判断promise是否处于Pending状态。
18 assertPromiseIsRejected @since1.0.4 判断promise是否处于Rejected状态。
19 assertPromiseIsRejectedWith @since1.0.4 判断promise是否处于Rejected状态,并且比较执行的结果值。
20 assertPromiseIsRejectedWithError @since1.0.4 判断promise是否处于Rejected状态并有异常,同时比较异常的类型和message值。
21 assertPromiseIsResolved @since1.0.4 判断promise是否处于Resolved状态。
22 assertPromiseIsResolvedWith @since1.0.4 判断promise是否处于Resolved状态,并且比较执行的结果值。
23 not @since1.0.4 断言取反,支持上面所有的断言功能

示例代码:

import { describe, it, expect } from '@ohos/hypium';
export default function abilityTest() {
  describe('ActsAbilityTest', () => {
    it('assertBeClose_success', 0, () => {
      let a:number = 100
      let b:number = 0.1
      expect(a).assertClose(99, b)
    })
    it('assertInstanceOf_success', 0, () => {
      let a: string = 'strTest'
      expect(a).assertInstanceOf('String')
    })
    it('assertNaN_success',0, () => {
      expect(Number.NaN).assertNaN(); // true
    })
    it('assertNegUnlimited_success',0, () => {
      expect(Number.NEGATIVE_INFINITY).assertNegUnlimited(); // true
    })
    it('assertPosUnlimited_success',0, () => {
      expect(Number.POSITIVE_INFINITY).assertPosUnlimited(); // true
    })
    it('not_number_true',0, () => {
      expect(1).not().assertLargerOrEqual(2)
    })
    it('not_number_true_1',0,() => {
      expect(3).not().assertLessOrEqual(2);
    })
    it('not_NaN_true',0, () => {
      expect(3).not().assertNaN();
    })
    it('not_contain_true',0,() => {
      let a: string = "abc";
      let b: string = "cdf"
      expect(a).not().assertContain(b);
    })
    it('not_large_true',0, () => {
      expect(3).not().assertLarger(4);
    })
    it('not_less_true',0, () => {
      expect(3).not().assertLess(2);
    })
    it('not_undefined_true',0, () => {
      expect(3).not().assertUndefined();
    })
    it('deepEquals_null_true',0, () => {
      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
      expect(null).assertDeepEquals(null)
    })
    it('deepEquals_array_not_have_true',0, () => {
      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
      const a: Array<number>= []
      const b: Array<number> = []
      expect(a).assertDeepEquals(b)
    })
    it('deepEquals_map_equal_length_success',0, () => {
      // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
      const a: Map<number, number> =  new Map();
      const b: Map<number, number> =  new Map();
      a.set(1,100);
      a.set(2,200);
      b.set(1, 100);
      b.set(2, 200);
      expect(a).assertDeepEquals(b)
    })
    it("deepEquals_obj_success_1", 0, () => {
      const a: SampleTest = {x:1};
    const b: SampleTest = {x:1};
  expect(a).assertDeepEquals(b);
})
it("deepEquals_regExp_success_0", 0, () => {
      const a: RegExp = new RegExp("/test/");
      const b: RegExp = new RegExp("/test/");
      expect(a).assertDeepEquals(b)
    })
it('test_isPending_pass_1', 0, () => {
      let p: Promise = new Promise<void>(() =>{
      });
      expect(p).assertPromiseIsPending();
    });
it('test_isRejected_pass_1', 0, () => {
  let info: PromiseInfo = {
  res:"no"
}
let p: Promise = Promise.reject(info);
expect(p).assertPromiseIsRejected();
});
it('test_isRejectedWith_pass_1', 0, () => {
  let info: PromiseInfo = {
  res:"reject value"
}
let p: Promise = Promise.reject(info);
expect(p).assertPromiseIsRejectedWith(info);
});
it('test_isRejectedWithError_pass_1', 0, () => {
  let p1: Promise = Promise.reject(new TypeError('number'));
  expect(p1).assertPromiseIsRejectedWithError(TypeError);
});
it('test_isResolved_pass_1', 0, () => {
  let info: PromiseInfo = {
  res:"result value"
}
let p: Promise = Promise.resolve(info);
expect(p).assertPromiseIsResolved();
});
it('test_isResolvedTo_pass_1', 0, () => {
  let info: PromiseInfo = {
  res:"result value"
}
let p: Promise = Promise.resolve(info);
expect(p).assertPromiseIsResolvedWith(info);
});
})
}
interface SampleTest {
  x: number;
}
interface PromiseInfo {
  res: string
}

Mock能力

约束限制

单元测试框架Mock能力从npm包1.0.1版本开始支持,需修改源码工程中package.info中配置依赖npm包版本号后使用。

  • 接口列表:
No. API 功能说明
1 mockFunc(obj: object, f:function()) mock某个类的对象obj的函数f,那么需要传两个参数:obj和f,支持使用异步函数(说明:对mock而言原函数实现是同步或异步没太多区别,因为mock并不关注原函数的实现)。
2 when(mockedfunc:function) 对传入后方法做检查,检查是否被mock并标记过,返回的是一个方法声明。
3 afterReturn(x:value) 设定预期返回一个自定义的值value,比如某个字符串或者一个promise。
4 afterReturnNothing() 设定预期没有返回值,即 undefined。
5 afterAction(x:action) 设定预期返回一个函数执行的操作。
6 afterThrow(x:msg) 设定预期抛出异常,并指定异常msg。
7 clear() 用例执行完毕后,进行数据mocker对象的还原处理(还原之后对象恢复被mock之前的功能)。
8 any 设定用户传任何类型参数(undefined和null除外),执行的结果都是预期的值,使用ArgumentMatchers.any方式调用。
9 anyString 设定用户传任何字符串参数,执行的结果都是预期的值,使用ArgumentMatchers.anyString方式调用。
10 anyBoolean 设定用户传任何boolean类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyBoolean方式调用。
11 anyFunction 设定用户传任何function类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyFunction方式调用。
12 anyNumber 设定用户传任何数字类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyNumber方式调用。
13 anyObj 设定用户传任何对象类型参数,执行的结果都是预期的值,使用ArgumentMatchers.anyObj方式调用。
14 matchRegexs(Regex) 设定用户传任何正则表达式类型参数Regex,执行的结果都是预期的值,使用ArgumentMatchers.matchRegexs(Regex)方式调用。
15 verify(methodName, argsArray) 验证methodName(函数名字符串)所对应的函数和其参数列表argsArray的执行行为是否符合预期,返回一个VerificationMode:一个提供验证模式的类,它有times(count)、once()、atLeast(x)、atMost(x)、never()等函数可供选择。
16 times(count) 验证行为调用过count次。
17 once() 验证行为调用过一次。
18 atLeast(count) 验证行为至少调用过count次。
19 atMost(count) 验证行为至多调用过count次。
20 never 验证行为从未发生过。
21 ignoreMock(obj, method) 使用ignoreMock可以还原obj对象中被mock后的函数,对被mock后的函数有效。
22 clearAll() 用例执行完毕后,进行数据和内存清理。
  • 使用示例:

用户可以通过以下方式进行引入mock模块进行测试用例编写:

  • 须知: 使用时候必须引入的mock能力模块: MockKit,when 根据自己用例需要引入断言能力api 例如:import { describe, expect, it, MockKit, when} from '@ohos/hypium'

示例1:afterReturn 的使用

import {describe, expect, it, MockKit, when} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }

        method_2(arg: string) {
          return '999999';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
when(mockfunc)('test').afterReturn('1');

//4.对mock后的函数进行断言,看是否符合预期
//执行成功案例,参数为'test'
expect(claser.method_1('test')).assertEqual('1'); //执行通过

//执行失败案例,参数为 'abc'
//expect(claser.method_1('abc')).assertEqual('1');//执行失败
});
});
}
  • 须知: when(mockfunc)('test').afterReturn('1'); 这句代码中的('test')是mock后的函数需要传递的匹配参数,目前支持一个参数 afterReturn('1')是用户需要预期返回的结果。 有且只有在参数是('test')的时候,执行的结果才是用户自定义的预期结果。

示例2: afterReturnNothing 的使用

import {describe, expect, it, MockKit, when} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }

        method_2(arg: string) {
          return '999999';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);

//4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterReturnNothing();即不返回任何值
when(mockfunc)('test').afterReturnNothing();

//5.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
//执行成功案例,参数为'test',这时候执行原对象claser.method_1的方法,会发生变化
// 这时候执行的claser.method_1不会再返回'888888',而是设定的afterReturnNothing()生效//不返回任何值;
expect(claser.method_1('test')).assertUndefined(); //执行通过

// 执行失败案例,参数传为 123
// expect(method_1(123)).assertUndefined();//执行失败
});
});
}

示例3: 设定参数类型为any ,即接受任何参数(undefine和null除外)的使用

  • 须知: 需要引入ArgumentMatchers类,即参数匹配器,例如:ArgumentMatchers.any
import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }

        method_2(arg: string) {
          return '999999';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
//根据自己需求进行选择参数匹配器和预期方法,
when(mockfunc)(ArgumentMatchers.any).afterReturn('1');

//4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
//执行成功的案例1,传参为字符串类型
expect(claser.method_1('test')).assertEqual('1'); //用例执行通过。
//执行成功的案例2,传参为数字类型123
expect(claser.method_1("123")).assertEqual('1');//用例执行通过。
//执行成功的案例3,传参为boolean类型true
expect(claser.method_1("true")).assertEqual('1');//用例执行通过。

//执行失败的案例,传参为数字类型空
//expect(claser.method_1()).assertEqual('1');//用例执行失败。
});
});
}

示例4: 设定参数类型ArgumentMatchers的使用

import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }

        method_2(arg: string) {
          return '999999';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
//根据自己需求进行选择
when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1');

//4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
//执行成功的案例,传参为字符串类型
expect(claser.method_1('test')).assertEqual('1'); //用例执行通过。
expect(claser.method_1('abc')).assertEqual('1'); //用例执行通过。

//执行失败的案例,传参为数字类型
//expect(claser.method_1(123)).assertEqual('1');//用例执行失败。
//expect(claser.method_1(true)).assertEqual('1');//用例执行失败。
});
});
}

示例5: 设定参数类型为matchRegexs(Regex)等 的使用

import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest',  () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }

        method_2(arg: string) {
          return '999999';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);
//根据自己需求进行选择
when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1');

//4.对mock后的函数进行断言,看是否符合预期,注意选择跟第4步中对应的断言方法
//执行成功的案例,传参为字符串类型
expect(claser.method_1('test')).assertEqual('1'); //用例执行通过。
expect(claser.method_1('abc')).assertEqual('1'); //用例执行通过。

//执行失败的案例,传参为数字类型
//expect(claser.method_1(123)).assertEqual('1');//用例执行失败。
//expect(claser.method_1(true)).assertEqual('1');//用例执行失败。
});
});
}

示例6: 验证功能 Verify函数的使用

 import {describe, expect, it, MockKit, when} from '@ohos/hypium';

 export default function ActsAbilityTest() {
  describe('ActsAbilityTest',  () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(...arg: string[]) {
          return '888888';
        }

        method_2(...arg: string[]) {
          return '999999';
        }
 }

 let claser: ClassName = new ClassName();

 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
 mocker.mockFunc(claser, claser.method_1);
 mocker.mockFunc(claser, claser.method_2);

 //4.方法调用如下
 claser.method_1('abc', 'ppp');
 claser.method_1('abc');
 claser.method_1('xyz');
 claser.method_1();
 claser.method_1('abc', 'xxx', 'yyy');
 claser.method_1();
 claser.method_2('111');
 claser.method_2('111', '222');

 //5.现在对mock后的两个函数进行验证,验证调用情况
 mocker.verify('method_1', []).atLeast(3); //结果为failed
 //解释:验证函数'method_1',参数列表为空:[] 的函数,至少执行过3次,
 //执行结果为failed,因为'method_1'且无参数 在4中只执行过2次
 //mocker.verify('method_2',['111']).once();//执行success,原因同上
 //mocker.verify('method_2',['111',,'222']).once();//执行success,原因同上
 });
 });
 } 

示例7: ignoreMock(obj, method) 忽略函数的使用

 import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium';

 export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker:MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(...arg: number[]) {
          return '888888';
        }

        method_2(...arg: number[]) {
          return '999999';
        }
 }

 let claser: ClassName = new ClassName();

 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
 let func_1: Function = mocker.mockFunc(claser, claser.method_1);
 let func_2: Function = mocker.mockFunc(claser, claser.method_2);

 //4.对mock后的函数的行为进行修改
 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4');
 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5');

 //5.方法调用如下
 console.log(claser.method_1(123)); //执行结果是4,符合步骤4中的预期
 console.log(claser.method_2(456)); //执行结果是5,符合步骤4中的预期

 //6.现在对mock后的两个函数的其中一个函数method_1进行忽略处理(原理是就是还原)
 mocker.ignoreMock(claser, claser.method_1);
 //然后再去调用 claser.method_1函数,看执行结果
 console.log(claser.method_1(123)); //执行结果是888888,发现这时结果跟步骤4中的预期不一样了,执行了claser.method_1没被mock之前的结果
 //用断言测试
 expect(claser.method_1(123)).assertEqual('4'); //结果为failed 符合ignoreMock预期
 claser.method_2(456); //执行结果是5,因为method_2没有执行ignore忽略,所有也符合步骤4中的预期
 });
 });
 }

示例8: clear()函数的使用

 import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium';

 export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(...arg: number[]) {
          return '888888';
        }

        method_2(...arg: number[]) {
          return '999999';
        }
 }

 let claser: ClassName = new ClassName();

 //3.进行mock操作,比如需要对ClassName类的method_1和method_2两个函数进行mock
 let func_1: Function = mocker.mockFunc(claser, claser.method_1);
 let func_2: Function = mocker.mockFunc(claser, claser.method_2);

 //4.对mock后的函数的行为进行修改
 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4');
 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5');

 //5.方法调用如下
 console.log(claser.method_1(123)); //执行结果是4,符合步骤4中的预期
 console.log(claser.method_2(456)); //执行结果是5,符合步骤4中的预期

 //6.现在对mock后的两个函数的其中一个函数method_1进行忽略处理(原理是就是还原)
 mocker.ignoreMock(claser, claser.method_1);
 //然后再去调用 claser.method_1函数,看执行结果
 console.log(claser.method_1(123)); //执行结果是888888,发现这时结果跟步骤4中的预期不一样了,执行了claser.method_1没被mock之前的结果
 //用断言测试
 expect(claser.method_1(123)).assertEqual('4'); //结果为failed 符合ignoreMock预期
 claser.method_2(456); //执行结果是5,因为method_2没有执行ignore忽略,所有也符合步骤4中的预期
 });
 });
 }

示例9: afterThrow(msg) 函数的使用

import {describe, expect, it, MockKit, when} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest',  () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        method_1(arg: string) {
          return '888888';
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);

//4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterReturnNothing();即不返回任何值
when(mockfunc)('test').afterThrow('error xxx');

//5.执行mock后的函数,捕捉异常并使用assertEqual对比msg否符合预期
try {
  claser.method_1('test');
} catch (e) {
  expect(e).assertEqual('error xxx');//执行通过
}
});
});
}

示例10: mock异步 函数的使用

import {describe, expect, it, MockKit, when} from '@ohos/hypium';

export default function ActsAbilityTest() {
  describe('ActsAbilityTest',  () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();

      //2.定类ClassName,里面两个函数,然后创建一个对象claser
      class ClassName {
        constructor() {
        }

        async method_1(arg: string) {
          return new Promise<string>((res: Function, rej: Function) => {
            //做一些异步操作
            setTimeout(() => {
              console.log('执行');
              res('数据传递');
            }, 2000);
          });
        }
}

let claser: ClassName = new ClassName();

//3.进行mock操作,比如需要对ClassName类的method_1函数进行mock
let mockfunc: Function = mocker.mockFunc(claser, claser.method_1);

//4.根据自己需求进行选择 执行完毕后的动作,比如这里选择afterRetrun; 可以自定义返回一个promise
when(mockfunc)('test').afterReturn(new Promise<string>((res: Function, rej: Function) => {
  console.log("do something");
  res('success something');
}));

//5.执行mock后的函数,即对定义的promise进行后续执行
claser.method_1('test').then((data: string) => {
  //数据处理代码...
  console.log('result : ' + data);
});
});
});
}

示例11:mock 系统函数的使用

import {describe, expect, it, MockKit, when} from '@ohos/hypium';
import app from '@system.app';
export default function ActsAbilityTest() {
  describe('ActsAbilityTest',  () => {
    it('testMockfunc', 0, () => {
      console.info("it1 begin");

      //1.创建一个mock能力的对象MockKit
      let mocker: MockKit = new MockKit();
      let mockf: Function = mocker.mockFunc(app, app.getInfo);
      when(mockf)().afterReturn('1');
      //执行成功案例
      expect(app.getInfo()).assertEqual('1');
    });
  });
}

示例12:verify times函数的使用(验证函数调用次数)

 import { describe, expect, it, MockKit, when } from '@ohos/hypium'

 export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('test_verify_times', 0, () => {
      //1.创建MockKit对象
      let mocker: MockKit = new MockKit();
      //2.定义需要被mock的类
      class ClassName {
        constructor() {
        }

        method_1(...arg: string[]) {
          return '888888';
        }
}
 //3.创建类对象
 let claser: ClassName = new ClassName();
 //4.mock 类ClassName对象的某个方法,比如method_1
 let func_1: Function = mocker.mockFunc(claser, claser.method_1);
 //5.期望被mock后的函数能够返回自己假设的结果
 when(func_1)('123').afterReturn('4');

 //6.随机执行几次函数,参数如下
 claser.method_1('123', 'ppp');
 claser.method_1('abc');
 claser.method_1('xyz');
 claser.method_1();
 claser.method_1('abc', 'xxx', 'yyy');
 claser.method_1('abc');
 claser.method_1();
 //7.验证函数method_1且参数为'abc'时,执行过的次数是否为2
 mocker.verify('method_1', ['abc']).times(2);
 });
 });
 }

示例13: verify atLeast 函数的使用 (验证函数调用次数)

import { describe, expect, it, MockKit, when } from '@ohos/hypium'

export default function ActsAbilityTest() {
  describe('ActsAbilityTest', () => {
    it('test_verify_atLeast', 0, () => {
      //1.创建MockKit对象
      let mocker: MockKit = new MockKit();
      //2.定义需要被mock的类
      class ClassName {
        constructor() {
        }

        method_1(...arg: string[]) {
          return '888888';
        }
}

//3.创建类对象
let claser: ClassName = new ClassName();
//4.mock  类ClassName对象的某个方法,比如method_1
let func_1: Function = mocker.mockFunc(claser, claser.method_1);
//5.期望被mock后的函数能够返回自己假设的结果
when(func_1)('123').afterReturn('4');
//6.随机执行几次函数,参数如下
claser.method_1('123', 'ppp');
claser.method_1('abc');
claser.method_1('xyz');
claser.method_1();
claser.method_1('abc', 'xxx', 'yyy');
claser.method_1();
//7.验证函数method_1且参数为空时,是否至少执行过2次
mocker.verify('method_1', []).atLeast(2);
});
});
}

数据驱动

约束限制

单元测试框架数据驱动能力从hypium 1.0.2版本开始支持。

  • 数据参数传递 : 为指定测试套、测试用例传递测试输入数据参数。
  • 压力测试 : 为指定测试套、测试用例设置执行次数。

数据驱动可以根据配置参数来驱动测试用例的执行次数和每一次传入的参数,使用时依赖data.json配置文件,文件内容如下:

说明 : data.json与测试用例*.test.js|ets文件同目录

{
	"suites": [{
		"describe": ["actsAbilityTest"],
		"stress": 2,
		"params": {
			"suiteParams1": "suiteParams001",
			"suiteParams2": "suiteParams002"
		},
		"items": [{
			"it": "testDataDriverAsync",
			"stress": 2,
			"params": [{
				"name": "tom",
				"value": 5
			}, {
				"name": "jerry",
				"value": 4
			}]
		}, {
			"it": "testDataDriver",
			"stress": 3
		}]
	}]
}

配置参数说明:

配置项名称 功能 必填
1 "suite" 测试套配置 。
2 "items" 测试用例配置 。
3 "describe" 测试套名称 。
4 "it" 测试用例名称 。
5 "params" 测试套 / 测试用例 可传入使用的参数 。
6 "stress" 测试套 / 测试用例 指定执行次数 。

示例代码:

在TestAbility目录下app.js|ets文件中导入data.json,并在Hypium.hypiumTest() 方法执行前,设置参数数据

import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
import { Hypium } from '@ohos/hypium'
import testsuite from '../test/List.test'
import data from '../test/data.json';

...
Hypium.setData(data);
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
...
 import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium';

 export default function abilityTest() {
  describe('actsAbilityTest', () => {
    it('testDataDriverAsync', 0, async (done: Function, data: ParmObj) => {
      console.info('name: ' + data.name);
      console.info('value: ' + data.value);
      done();
    });

    it('testDataDriver', 0, () => {
      console.info('stress test');
    });
  });
}
 interface ParmObj {
   name: string,
   value: string
 }

专项能力

该项能力需通过在cmd窗口中输入aa test命令执行触发,并通过设置执行参数触发不同功能。另外,测试应用模型与编译方式不同,对应的aa test命令也不同,具体可参考自动化测试框架使用指导

  • 筛选能力

    1、按测试用例属性筛选

    可以利用hypium提供的Level、Size、TestType 对象,对测试用例进行标记,以区分测试用例的级别、粒度、测试类型,各字段含义及代码如下:

    Key 含义说明 Value取值范围
    level 用例级别 "0","1","2","3","4", 例如:-s level 1
    size 用例粒度 "small","medium","large", 例如:-s size small
    testType 用例测试类型 "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function

    示例代码:

import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';

export default function attributeTest() {
 describe('attributeTest', () => {
   it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
     console.info('Hello Test');
   })
 })
}

示例命令:

hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s testType function -s size small -s level 0

该命令作用是筛选测试应用中同时满足,用例测试类型是“function”、用例粒度是“small”、用例级别是“0”的三个条件用例执行。

2、按测试套/测试用例名称筛选

hypium可以通过指定测试套与测试用例名称,来指定特定用例的执行,测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔

Key 含义说明 Value取值范围
class 指定要执行的测试套&用例 ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt
notClass 指定不执行的测试套&用例 ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttribut

示例代码:

import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';

export default function attributeTest() {
describe('describeTest_000',  () => {
  it("testIt_00", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0,  () => {
    console.info('Hello Test');
  })

  it("testIt_01", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
    console.info('Hello Test');
  })
})

describe('describeTest_001',  () => {
  it("testIt_02", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, () => {
    console.info('Hello Test');
  })
})
}

示例命令1:

hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s class describeTest_000#testIt_00,describeTest_001

该命令作用是执行“describeTest_001”测试套中所用用例,以及“describeTest_000”测试套中的“testIt_00”用例。

示例命令2:

hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s notClass describeTest_000#testIt_01

该命令作用是不执行“describeTest_000”测试套中的“testIt_01”用例。

  • 随机执行

    使测试套与测试用例随机执行,用于稳定性测试。

    Key 含义说明 Value取值范围
    random @since1.0.3 测试套、测试用例随机执行 true, 不传参默认为false, 例如:-s random true

    示例命令:

    hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s dryRun true
  • 压力测试

    指定要执行用例的执行次数,用于压力测试。

    Key 含义说明 Value取值范围
    stress @since1.0.5 指定要执行用例的执行次数 正整数, 例如: -s stress 1000

    示例命令:

    hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s stress 1000
  • 用例超时时间设置

    指定测试用例执行的超时时间,用例实际耗时如果大于超时时间,用例会抛出"timeout"异常,用例结果会显示“excute timeout XXX”

    Key 含义说明 Value取值范围
    timeout 指定测试用例执行的超时时间 正整数(单位ms),默认为 5000,例如: -s timeout 15000

    示例命令:

    hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s timeout 15000
  • 遇错即停模式

    Key 含义说明 Value取值范围
    breakOnError @since1.0.6 遇错即停模式,当执行用例断言失败或者发生错误时,退出测试执行流程 true, 不传参默认为false, 例如:-s breakOnError true

    示例命令:

    hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s breakOnError true
  • 测试套中用例信息输出

    输出测试应用中待执行的测试用例信息

    Key 含义说明 Value取值范围
    dryRun 显示待执行的测试用例信息全集 true, 不传参默认为false, 例如:-s dryRun true

    示例命令:

    hdc shell aa test -b xxx -m xxx -s unittest OpenHarmonyTestRunner -s dryRun true

使用方式

单元测试框架以npm包(hypium)形式发布至服务组件官网,开发者可以下载Deveco Studio后,在应用工程中配置依赖后使用框架能力,测试工程创建及测试脚本执行使用指南请参见IDE指导文档

Ui测试框架功能特性

No. 特性 功能说明
1 Driver Ui测试的入口,提供查找控件,检查控件存在性以及注入按键能力。
2 On 用于描述目标控件特征(文本、id、类型等),Driver根据On描述的控件特征信息来查找控件。
3 Component Driver查找返回的控件对象,提供查询控件属性,滑动查找等触控和检视能力。
4 UiWindow Driver查找返回的窗口对象,提供获取窗口属性、操作窗口的能力。

使用者在测试脚本通过如下方式引入使用:

import {Driver,ON,Component,UiWindow,MatchPattern} from '@ohos.UiTest'

须知

  1. On类提供的接口全部是同步接口,使用者可以使用builder模式链式调用其接口构造控件筛选条件。
  2. DriverComponent类提供的接口全部是异步接口(Promise形式),需使用await语法
  3. Ui测试用例均需使用异步语法编写用例,需遵循单元测试框架异步用例编写规范。

在测试用例文件中import On/Driver/Component类,然后调用API接口编写测试用例。

 import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium'
 import {ON, Driver, Component, MatchPattern} from '@ohos.UiTest'

 export default async function abilityTest() {
  describe('uiTestDemo', () => {
    it('uitest_demo0', 0, async () => {
      // create Driver
      let driver: Driver = Driver.create()
      // find component by text
      let button: Component = await driver.findComponent(ON.text('hello').enabled(true))
      // click component
      await button.click()
      // get and assert component text
      let content: string = await button.getText()
      expect(content).assertEqual('clicked!')
    })
  })
}

Driver使用说明

Driver类作为UiTest测试框架的总入口,提供查找控件,注入按键,单击坐标,滑动控件,手势操作,截图等能力。

No. API 功能描述
1 create():Promise 静态方法,构造Driver。
2 findComponent(on:On):Promise 查找匹配控件。
3 pressBack():Promise 单击BACK键。
4 click(x:number, y:number):Promise 基于坐标点的单击。
5 swipe(x1:number, y1:number, x2:number, y2:number):Promise 基于坐标点的滑动。
6 assertComponentExist(on:On):Promise 断言匹配的控件存在。
7 delayMs(t:number):Promise 延时。
8 screenCap(s:path):Promise 截屏。
9 findWindow(filter: WindowFilter): Promise 查找匹配窗口。

其中assertComponentExist接口是断言API,用于断言当前界面存在目标控件;如果控件不存在,该API将抛出JS异常,使当前测试用例失败。

 import { Driver, ON } from '@ohos.UiTest';
 import { describe, it} from '@ohos/hypium';
 export default async function abilityTest() {
  describe('UiTestDemo', () => {
    it('Uitest_demo0', 0, async (done: Function) => {
      try{
        // create Driver
        let driver: Driver = Driver.create()
        // assert text 'hello' exists on current Ui
        await driver.assertComponentExist(ON.text('hello'))
      } finally {
        done()
      }
    })
  })
}

Driver完整的API列表请参考API文档示例文档说明

On使用说明

Ui测试框架通过On类提供了丰富的控件特征描述API,用来匹配查找要操作或检视的目标控件。On提供的API能力具有以下特点:

  • 支持匹配单属性和匹配多属性组合,例如同时指定目标控件text和id。
  • 控件属性支持多种匹配模式(等于,包含,STARTS_WITHENDS_WITH)。
  • 支持相对定位控件,可通过isBeforeisAfter等API限定邻近控件特征进行辅助定位。
No. API 功能描述
1 id(i:string):On 指定控件id。
2 text(t:string, p?:MatchPattern):On 指定控件文本,可指定匹配模式。
3 type(t:string):On 指定控件类型。
4 enabled(e:bool):On 指定控件使能状态。
5 clickable(c:bool):On 指定控件可单击状态。
6 longClickable(l:bool):On 指定控件可长按状态。
7 focused(f:bool):On 指定控件获焦状态。
8 scrollable(s:bool):On 指定控件可滑动状态。
9 selected(s:bool):On 指定控件选中状态。
10 checked(c:bool):On 指定控件选择状态。
11 checkable(c:bool):On 指定控件可选择状态。
12 isBefore(b:On):On 相对定位,限定目标控件位于指定特征控件之前。
13 isAfter(b:On):On 相对定位,限定目标控件位于指定特征控件之后。

其中,text属性支持{MatchPattern.EQUALSMatchPattern.CONTAINSMatchPattern.STARTS_WITHMatchPattern.ENDS_WITH}四种匹配模式,缺省使用MatchPattern.EQUALS模式。

On完整的API列表请参考API文档示例文档说明

控件绝对定位

示例代码1:查找id是Id_button的控件。

let button: Component = await driver.findComponent(ON.id('Id_button'))

示例代码2:查找id是Id_button并且状态是enabled的控件,适用于无法通过单一属性定位的场景。

let button: Component = await driver.findComponent(ON.id('Id_button').enabled(true))

通过On.id(x).enabled(y)来指定目标控件的多个属性。

示例代码3:查找文本中包含hello的控件,适用于不能完全确定控件属性取值的场景。

let txt: Component = await driver.findComponent(ON.text('hello', MatchPattern.CONTAINS))

通过向On.text()方法传入第二个参数MatchPattern.CONTAINS来指定文本匹配规则;默认规则是MatchPattern.EQUALS,即目标控件text属性必须严格等于给定值。

控件相对定位

示例代码1:查找位于文本控件Item3_3后面的,id是Id_switch的Switch控件。

let switch: Component = await driver.findComponent(ON.id('Id_switch').isAfter(ON.text('Item3_3')))

通过On.isAfter方法,指定位于目标控件前面的特征控件属性,通过该特征控件进行相对定位。一般地,特征控件是某个具有全局唯一特征的控件(例如具有唯一的id或者唯一的text)。

类似的,可以使用On.isBefore控件指定位于目标控件后面的特征控件属性,实现相对定位。

Component使用说明

Component类代表了Ui界面上的一个控件,一般是通过Driver.findComponent(on)方法查找到的。通过该类的实例,用户可以获取控件属性,单击控件,滑动查找,注入文本等操作。

Component包含的常用API:

No. API 功能描述
1 click():Promise 单击该控件。
2 inputText(t:string):Promise 向控件中输入文本(适用于文本框控件)。
3 scrollSearch(s:On):Promise 在该控件上滑动查找目标控件(适用于List等控件)。
4 scrollToTop(s:number):Promise 滑动到该控件顶部(适用于List等控件)。
5 scrollTobottom(s:number):Promise 滑动到该控件底部(适用于List等控件)。
6 getText():Promise 获取控件text。
7 getId():Promise 获取控件id。
8 getType():Promise 获取控件类型。
9 isEnabled():Promise 获取控件使能状态。

Component完整的API列表请参考API文档示例文档说明

示例代码1:单击控件。

let button: Component = await driver.findComponent(ON.id('Id_button'))
await button.click()

示例代码2:通过get接口获取控件属性后,可以使用单元测试框架提供的assert*接口做断言检查。

let component: Component = await driver.findComponent(ON.id('Id_title'))
expect(component !== null).assertTrue()

示例代码3:在List控件中滑动查找text是Item3_3的子控件。

let list: Component = await driver.findComponent(ON.id('Id_list'))
let found: Component = await list.scrollSearch(ON.text('Item3_3'))
expect(found).assertTrue()

示例代码4:向输入框控件中输入文本。

let editText: Component = await driver.findComponent(ON.type('InputText'))
await editText.inputText('user_name')

UiWindow使用说明

UiWindow类代表了Ui界面上的一个窗口,一般是通过Driver.findWindow(WindowFilter)方法查找到的。通过该类的实例,用户可以获取窗口属性,并进行窗口拖动、调整窗口大小等操作。

UiWindow包含的常用API:

No. API 功能描述
1 getBundleName(): Promise 获取窗口所属应用包名。
2 getTitle(): Promise 获取窗口标题信息。
3 focus(): Promise 使得当前窗口获取焦点。
4 moveTo(x: number, y: number): Promise 将当前窗口移动到指定位置(适用于支持移动的窗口)。
5 resize(wide: number, height: number, direction: ResizeDirection): Promise 调整窗口大小(适用于支持调整大小的窗口)。
6 split(): Promise 将窗口模式切换为分屏模式(适用于支持分屏的窗口)。
7 close(): Promise 关闭当前窗口。

UiWindow完整的API列表请参考API文档示例文档说明

示例代码1:获取窗口属性。

let window: UiWindow = await driver.findWindow({actived: true})
let bundelName: string = await window.getBundleName()

示例代码2:移动窗口。

let window: UiWindow = await driver.findWindow({actived: true})
await window.moveTo(500,500)

示例代码3:关闭窗口。

let window: UiWindow = await driver.findWindow({actived: true})
await window.close()

使用方式

开发者可以下载Deveco Studio创建测试工程后,在其中调用框架提供接口进行相关测试操作,测试工程创建及测试脚本执行使用指南请参见IDE指导文档。 UI测试框架使能需要执行如下命令。

hdc shell param set persist.ace.testmode.enabled 1

UI测试框架自构建方式

Ui测试框架在OpenHarmony-3.1-Release版本中未随版本编译,需手动处理,请参考3.1-Release版本使用指导

开发者如需自行编译Ui测试框架代码验证子修改内容,构建命令和推送位置请参考本章节内容。

构建命令

./build.sh --product-name rk3568 --build-target uitestkit

推送位置

hdc target mount
hdc shell mount -o rw,remount /
hdc file send uitest /system/bin/uitest
hdc file send libuitest.z.so /system/lib/module/libuitest.z.so
hdc shell chmod +x /system/bin/uitest

命令行使用说明

开发者可以输入如下命令来实现对应功能。

1、打印使用帮助

hdc shell uitest help

2、截屏

hdc shell uitest screenCap
// 默认存储路径:/data/local/tmp,文件名:时间戳 + .png。
hdc shell uitest screenCap -p /data/local/1.png
// 指定存储路径和文件名。

3、获取设备当前Ui控件树信息

hdc shell uitest dumpLayout
// 默认存储路径:/data/local/tmp,文件名:时间戳 + .json。
hdc shell uitest screenCap -p /data/local/1.json
// 指定存储路径和文件名。

4、录制Ui操作

hdc shell uitest uiRecord record
// 将当前执行的Ui操作记录到/data/local/tmp/layout/record.csv
hdc shell uitest uiRecord read
// 将记录的Ui操作打印出来

5、 shell命令方式注入UI模拟操作

支持操作类型:点击 双击 长按 慢滑 快滑 拖拽 输入文字 KeyEvent。

配置参数值 配置参数含义 配置参数有值 示例
click 模拟单击操作 point_x (必选参数,点击x坐标点)
point_y (必选参数,点击y坐标点)
hdc shell uitest uiInput click point_x point_y
doubleClick 模拟双击操作 point_x (必选参数,双击x坐标点)
point_y (必选参数,双击y坐标点)
hdc shell uitest uiInput doubleClick point_x point_y
longClick 模拟长按操作 point_x (必选参数,长按x坐标点)
point_y (必选参数,长按y坐标点)
hdc shell uitest uiInput longClick point_x point_y
fling 模拟快滑操作 from_x (必选参数,滑动起点x坐标)
from_y(必选参数,滑动起点y坐标)
to_x(必选参数,滑动终点x坐标)
to_y(必选参数,滑动终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600)
stepLength(可选参数,滑动步长,默认值:滑动距离/50)
hdc shell uitest uiInput fling from_x from_y to_x to_y swipeVelocityPps_ stepLength
swipe 模拟慢滑操作 from_x (必选参数,滑动起点x坐标)
from_y(必选参数,滑动起点y坐标)
to_x(必选参数,滑动终点x坐标)
to_y(必选参数,滑动终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600))
hdc shell uitest uiInput swipe from_x from_y to_x to_y swipeVelocityPps_
drag 模拟拖拽操作 from_x (必选参数,拖拽起点x坐标)
from_y(必选参数,拖拽起点y坐标)
to_x(必选参数,拖拽终点x坐标)
to_y(必选参数,拖拽终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600))
hdc shell uitest uiInput drag from_x from_y to_x to_y swipeVelocityPps_
dircFling 模拟指定方向滑动操作 direction (可选参数,滑动方向,可选值: [0,1,2,3], 滑动方向: [左,右,上,下],默认值: 0)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600)
stepLength(可选参数,滑动步长,默认值:滑动距离/50)
hdc shell uitest uiInput dircFling direction swipeVelocityPps_ stepLength
inputText 模拟输入框输入文本操作 point_x (必选参数,输入框x坐标点)
point_y (必选参数,输入框y坐标点)
input(输入文本)
hdc shell uitest uiInput inputText point_x point_y text
keyEvent 模拟实体按键事件(如:键盘,电源键,返回上一级,返回桌面等),以及组合按键操作 keyID (必选参数,实体按键对应ID)
keyID2 (可选参数,实体按键对应ID)
hdc shell uitest uiInput keyEvent keyID

示例代码1:执行点击事件。

 hdc shell uitest uiInput click 100 100

示例代码2:执行双击事件。

 hdc shell uitest uiInput doubleClick 100 100

示例代码3:执行长按事件。

 hdc shell uitest uiInput longClick 100 100

示例代码4:执行快滑操作。

hdc shell uitest uiInput fling 10 10 200 200 500 

示例代码5:执行慢滑操作。

hdc shell uitest uiInput swipe 10 10 200 200 500 

示例代码6:执行拖拽操作。

hdc shell uitest uiInput drag 10 10 100 100 500 

示例代码7:执行向左滑动操作。

hdc shell uitest uiInput dircFling 0 500

示例代码8:执行向右滑动操作。

hdc shell uitest uiInput dircFling 1 600

示例代码9:执行向上滑动操作。

hdc shell uitest uiInput dircFling 2 

示例代码10:执行向下滑动操作。

hdc shell uitest uiInput dircFling 3

示例代码11:执行输入框输入操作。

hdc shell uitest uiInput inputText 100 100 hello

示例代码12:执行返回主页操作。

hdc shell uitest uiInput keyEvent Home

示例代码13:执行返回上一步操作。

hdc shell uitest uiInput keyEvent Back

示例代码14:执行组合键粘贴操作。

hdc shell uitest uiInput keyEvent 2072 2038

版本信息

版本号 功能说明
3.2.2.1 1、增加抛滑、获取/设置屏幕方向接口
2、窗口处理逻辑增加不支持场景处理逻辑
3.2.3.0 1、滑动控件进行滑动查找、滑动到尾部/顶部功能优化
3.2.4.0 1、接口调用异常时会抛出错误码
3.2.5.0 1、通信机制变更
3.2.6.0 1、增加模拟鼠标操作能力接口
2、增加指定应用的窗口下查找目标控件接口
4.0.1.1 1、支持在daemon运行时执行uitest dumpLayout
4.0.1.2 1、模拟鼠标动作、键鼠协同功能优化
4.0.1.3 1、示例代码更新
2、滑动控件进行滑动查找、滑动到尾部/顶部功能优化
4.0.1.4 1、可选参数传入undefined时,当作默认值处理
4.0.2.0 1、支持监听toast和dialog控件出现,使用callback的形式返回结果。
4.0.3.0 1、增加加载运行.abc文件机制。
4.0.4.0 1、支持abc_loader框架获取UI操作录制数据,屏幕数据,控件树等,并以callback的形式返回结果
2、修改录制数据结构
4.1.1.1 1、对接批量获取控件信息能力,缩短获取控件信息的耗时。
4.1.2.0 1、增加shell命令方式注入UI模拟操作。
4.1.3.0 1、新增命令行功能,uitest dumuLayout -a ,dump信息中包含控件的背景色、字体颜色/大小信息。
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS

简介

OpenHarmony Test Framework | OpenHarmony 自动化测试框架 展开 收起
C++ 等 3 种语言
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/openharmony/testfwk_arkxtest.git
git@gitee.com:openharmony/testfwk_arkxtest.git
openharmony
testfwk_arkxtest
testfwk_arkxtest
master

搜索帮助