
鸿蒙5 UI自动化测试:DevEco Studio测试脚本编写实战指南
一、鸿蒙5 UI自动化测试概述
鸿蒙5在ArkCompiler的支持下,提供了全新的UI自动化测试框架,主要特性包括:
跨语言支持:兼容JS/TS测试脚本
多设备适配:自动适配不同屏幕尺寸
智能识别:支持ID、文本、类型等多种元素定位方式
集成报告:生成详细的测试执行报告
二、测试环境配置
- 创建测试模块
在DevEco Studio中:
右键项目 → New → Module
选择 “Test” 模块类型
配置测试模块名称(如 “test”)
2. 测试目录结构
test/
├── src/
│ ├── main/
│ │ ├── resources/
│ │ └── module.json5
│ └── test/
│ ├── js/
│ │ └── test/
│ │ └── Example.test.ets
│ └── resources/
└── oh-package.json5
3. 配置测试依赖
oh-package.json5:
{
“devDependencies”: {
“@ohos/hypium”: “^1.0.0”
}
}
三、基础测试脚本编写
- 测试用例结构
// Example.test.ets
import { describe, it, expect } from ‘@ohos/hypium’;
import abilityTest from ‘@ohos/abilityTest’;
export default function testRunner() {
describe(‘AppTest’, function() {
it(‘StartAbility’, 0, async function() {
try {
await abilityTest.startAbility({
bundleName: ‘com.example.myapp’,
abilityName: ‘EntryAbility’
});
expect(true).assertTrue();
} catch (err) {
expect(err).assertNull();
}
});
});
}
2. 元素定位与操作
import { by, Component, ON } from ‘@ohos/hypium’;
it(‘ButtonClickTest’, 0, async function() {
// 通过ID定位按钮
const submitBtn = await ON.component(by.id(‘submit_button’));
// 验证元素存在
expect(await submitBtn.isDisplayed()).assertTrue();
// 点击操作
await submitBtn.click();
// 验证结果
const resultText = await ON.component(by.text(‘操作成功’));
expect(await resultText.isDisplayed()).assertTrue();
});
四、高级测试技术
- 页面跳转测试
it(‘NavigationTest’, 0, async function() {
// 初始页面验证
expect(await ON.component(by.id(‘home_page’)).isDisplayed()).assertTrue();
// 跳转到详情页
await ON.component(by.id(‘detail_btn’)).click();
// 等待页面加载
await ON.delay(1000);
// 验证详情页元素
expect(await ON.component(by.id(‘detail_page’)).isDisplayed()).assertTrue();
// 返回首页
await ON.component(by.id(‘back_btn’)).click();
// 验证返回结果
expect(await ON.component(by.id(‘home_page’)).isDisplayed()).assertTrue();
});
2. 列表操作测试
it(‘ListScrollTest’, 0, async function() {
// 获取列表组件
const newsList = await ON.component(by.id(‘news_list’));
// 验证列表存在
expect(await newsList.isDisplayed()).assertTrue();
// 滚动列表
await newsList.scrollToEnd();
// 获取列表项数量
const items = await newsList.findComponents(by.type(‘ListItem’));
expect(items.length).assertLarger(5);
// 点击最后一项
await items[items.length - 1].click();
// 验证详情页打开
expect(await ON.component(by.id(‘news_detail’)).isDisplayed()).assertTrue();
});
3. 输入操作测试
it(‘InputTest’, 0, async function() {
// 定位输入框
const usernameInput = await ON.component(by.id(‘username_input’));
// 输入文本
await usernameInput.inputText(‘testuser’);
// 验证输入内容
expect(await usernameInput.getText()).assertEqual(‘testuser’);
// 定位密码框
const passwordInput = await ON.component(by.id(‘password_input’));
// 输入密码
await passwordInput.inputText(‘123456’);
// 点击登录
await ON.component(by.id(‘login_btn’)).click();
// 验证登录结果
expect(await ON.component(by.text(‘登录成功’)).isDisplayed()).assertTrue();
});
五、测试数据驱动
- 参数化测试
const testCases = [
{ username: ‘admin’, password: ‘admin123’, expected: true },
{ username: ‘test’, password: ‘wrong’, expected: false },
{ username: ‘’, password: ‘’, expected: false }
];
testCases.forEach((caseData, index) => {
it(LoginTest_${index}
, 0, async function() {
// 输入用户名
await ON.component(by.id(‘username_input’)).inputText(caseData.username);
// 输入密码
await ON.component(by.id('password_input')).inputText(caseData.password);
// 点击登录
await ON.component(by.id('login_btn')).click();
// 验证结果
if (caseData.expected) {
expect(await ON.component(by.text('登录成功')).isDisplayed()).assertTrue();
} else {
expect(await ON.component(by.text('登录失败')).isDisplayed()).assertTrue();
}
// 返回登录页
if (await ON.component(by.id('back_btn')).isDisplayed()) {
await ON.component(by.id('back_btn')).click();
}
});
});
2. 外部数据文件
test/resources/login_data.json:
[
{ “username”: “user1”, “password”: “pass1”, “expected”: true },
{ “username”: “user2”, “password”: “pass2”, “expected”: false }
]
测试脚本中使用:
import data from ‘…/…/resources/login_data.json’;
data.forEach((caseData, index) => {
it(DataDrivenLogin_${index}
, 0, async function() {
// 测试逻辑同上
});
});
六、测试套件组织
- 测试套件定义
// SmokeTestSuite.ets
import { describe } from ‘@ohos/hypium’;
export default function smokeTestSuite() {
describe(‘SmokeTest’, function() {
require(‘./LoginTest.ets’);
require(‘./HomePageTest.ets’);
require(‘./ProfileTest.ets’);
});
}
// RegressionTestSuite.ets
import { describe } from ‘@ohos/hypium’;
export default function regressionTestSuite() {
describe(‘RegressionTest’, function() {
require(‘./FullFlowTest.ets’);
require(‘./PerformanceTest.ets’);
require(‘./CompatibilityTest.ets’);
});
}
2. 主测试入口
test/src/test/js/test/index.ets:
import smokeTest from ‘./SmokeTestSuite’;
import regressionTest from ‘./RegressionTestSuite’;
export default function mainTestRunner() {
smokeTest();
regressionTest();
}
七、高级技巧与最佳实践
- 自定义匹配器
import { Matcher } from ‘@ohos/hypium’;
class CustomMatcher extends Matcher {
async toBeVisible(component: Component) {
const isDisplayed = await component.isDisplayed();
return {
pass: isDisplayed,
message: Expected component to ${this.isNot ? 'not ' : ''}be visible
};
}
}
// 注册自定义匹配器
expect.extend(new CustomMatcher());
// 使用示例
it(‘CustomMatcherTest’, 0, async function() {
const btn = await ON.component(by.id(‘my_button’));
await expect(btn).toBeVisible();
});
2. 页面对象模式
test/src/test/js/test/pages/LoginPage.ets:
export default class LoginPage {
static async inputUsername(text: string) {
await ON.component(by.id(‘username_input’)).inputText(text);
}
static async inputPassword(text: string) {
await ON.component(by.id(‘password_input’)).inputText(text);
}
static async clickLogin() {
await ON.component(by.id(‘login_btn’)).click();
}
static async isLoginSuccess() {
return await ON.component(by.text(‘登录成功’)).isDisplayed();
}
}
// 测试脚本中使用
it(‘LoginWithPageObject’, 0, async function() {
await LoginPage.inputUsername(‘admin’);
await LoginPage.inputPassword(‘admin123’);
await LoginPage.clickLogin();
expect(await LoginPage.isLoginSuccess()).assertTrue();
});
3. 测试钩子
import { beforeAll, afterEach, afterAll } from ‘@ohos/hypium’;
describe(‘AuthTest’, function() {
beforeAll(async function() {
// 测试前置操作
await abilityTest.startAbility({
bundleName: ‘com.example.myapp’,
abilityName: ‘EntryAbility’
});
});
afterEach(async function() {
// 每个测试用例后执行
await ON.component(by.id(‘logout_btn’)).click();
});
afterAll(function() {
// 所有测试完成后执行
console.log(‘AuthTest completed’);
});
// 测试用例…
});
八、测试报告与调试
- 生成测试报告
运行测试命令:
hdc shell aa test -b com.example.myapp -m test -s unittest OpenHarmonyTestRunner -s class com.example.myapp.test.Runner
测试报告位置:
/data/test/runner/resource/report/
2. 测试截图
it(‘ScreenshotTest’, 0, async function() {
// 执行操作…
await ON.component(by.id(‘some_button’)).click();
// 截图
const screenshotPath = ‘/data/test/screenshots/’;
await ON.captureScreen(screenshotPath + ‘after_click.png’);
// 验证截图存在
const file = await fileIo.open(screenshotPath + ‘after_click.png’);
expect(file).not().assertNull();
file.close();
});
3. 测试日志
import { Logger } from ‘@ohos/hypium’;
it(‘LoggingTest’, 0, async function() {
Logger.info(‘Starting login test’);
try {
await LoginPage.inputUsername(‘testuser’);
Logger.debug(‘Username entered’);
await LoginPage.inputPassword('testpass');
Logger.debug('Password entered');
await LoginPage.clickLogin();
Logger.info('Login button clicked');
expect(await LoginPage.isLoginSuccess()).assertTrue();
} catch (err) {
Logger.error(Test failed: ${err}
);
throw err;
}
});
九、持续集成配置
- GitHub Actions 示例
.github/workflows/test.yml:
name: UI Automation Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install DevEco CLI
run: npm install -g @ohos/deveco-cli
- name: Run Tests
run: |
deveco test --module test --device emulator
- name: Upload Reports
uses: actions/upload-artifact@v2
with:
name: test-reports
path: test/build/reports/
- 本地测试命令
运行单个测试模块
deveco test --module test --device emulator
运行特定测试套件
deveco test --module test --device emulator --suite SmokeTest
生成HTML报告
deveco test --report html
十、总结与最佳实践
- 测试金字塔实践
单元测试:覆盖核心业务逻辑
组件测试:验证UI组件行为
UI自动化测试:覆盖关键用户流程 - 测试设计原则
原子性:每个测试只验证一个功能点
独立性:测试之间不依赖执行顺序
可重复性:在任何环境都能稳定运行
可读性:清晰的测试命名和结构 - 性能优化建议
使用beforeAll共享初始化操作
避免不必要的UI操作
合理使用delay等待元素出现
并行执行独立测试用例
鸿蒙5的UI自动化测试框架结合ArkCompiler的优化,为开发者提供了强大的测试能力。通过本文介绍的技术方案,开发者可以构建出高效、可靠的自动化测试套件,确保应用质量。随着鸿蒙生态的发展,这套测试方案将支持更丰富的测试场景和设备类型。
