HarmonyOS测试与上架:单元测试、UI测试与App Gallery Connect发布实战

本文将全面介绍HarmonyOS应用的测试策略和上架流程,涵盖从单元测试到应用市场发布的完整生命周期管理,帮助开发者构建高质量、可发布的HarmonyOS应用。

一、HarmonyOS测试体系概述

HarmonyOS提供了完整的测试解决方案,从代码级别的单元测试到UI界面测试,再到分布式场景测试,确保应用在各种场景下的稳定性和可靠性。

1.1 测试金字塔模型

HarmonyOS应用测试遵循经典的测试金字塔模型,从底层到顶层分别为:

测试层次结构:
• 单元测试:验证单个函数、类的正确性(占比70%)

• 集成测试:验证模块间协作的正确性(占比20%)

• UI测试:验证用户界面交互的正确性(占比10%)

• 分布式测试:验证跨设备功能的正确性(特殊场景)

1.2 测试环境配置

在开始测试前,需要配置完整的测试环境:

DevEco Studio测试配置:
// build-profile.json5中的测试配置
{
"buildOps": {
"testConfig": {
"testRunner": "ohosTestRunner",
"testPackage": "test",
"testSources": ["src/test/ets"],
"testResources": ["src/test/resources"]
}
}
}

二、单元测试实战

单元测试是保证代码质量的基础,HarmonyOS使用基于JUnit的测试框架。

2.1 单元测试环境搭建

测试依赖配置(oh-package.json5):
{
"devDependencies": {
"@ohos/hypium": "^1.0.0",
"@ohos/testRunner": "^1.0.0"
}
}

基础测试类结构:
// tests/ExampleTest.ets
import { describe, it, expect } from '@ohos/hypium';
import Calculator from '../../main/ets/calculator/Calculator';

export default function ExampleTest() {
describe('CalculatorTest', () => {
it('testAddition', 0, () => {
const calculator = new Calculator();
const result = calculator.add(2, 3);
expect(result).assertEqual(5);
});

it('testSubtraction', 0, () => {
  const calculator = new Calculator();
  const result = calculator.subtract(5, 3);
  expect(result).assertEqual(2);
});

it('testMultiplication', 0, () => {
  const calculator = new Calculator();
  const result = calculator.multiply(4, 3);
  expect(result).assertEqual(12);
});

it('testDivision', 0, () => {
  const calculator = new Calculator();
  const result = calculator.divide(10, 2);
  expect(result).assertEqual(5);
});

});
}

2.2 业务逻辑单元测试

针对实际业务场景的单元测试示例:
// tests/UserServiceTest.ets
import { describe, it, expect, beforeEach } from '@ohos/hypium';
import UserService from '../../main/ets/service/UserService';
import MockDatabase from '../mock/MockDatabase';

export default function UserServiceTest() {
describe('UserServiceTest', () => {
let userService: UserService;
let mockDb: MockDatabase;

beforeEach(() => {
  mockDb = new MockDatabase();
  userService = new UserService(mockDb);
});

it('testUserRegistration', 0, () => {
  const userData = {
    username: 'testuser',
    email: 'test@example.com',
    password: 'securepassword'
  };

  const result = userService.register(userData);
  expect(result.success).assertTrue();
  expect(result.userId).assertNotNull();
});

it('testDuplicateUserRegistration', 0, () => {
  const userData = {
    username: 'existinguser',
    email: 'existing@example.com',
    password: 'password'
  };

  // 先注册一次
  userService.register(userData);
  
  // 尝试重复注册
  const result = userService.register(userData);
  expect(result.success).assertFalse();
  expect(result.error).assertEqual('USER_ALREADY_EXISTS');
});

it('testUserLogin', 0, () => {
  const credentials = {
    username: 'testuser',
    password: 'correctpassword'
  };

  const loginResult = userService.login(credentials);
  expect(loginResult.authenticated).assertTrue();
  expect(loginResult.sessionToken).assertNotNull();
});

it('testUserLoginWithWrongPassword', 0, () => {
  const credentials = {
    username: 'testuser',
    password: 'wrongpassword'
  };

  const loginResult = userService.login(credentials);
  expect(loginResult.authenticated).assertFalse();
  expect(loginResult.error).assertEqual('INVALID_CREDENTIALS');
});

});
}

2.3 异步操作测试

处理异步代码的测试策略:
// tests/NetworkServiceTest.ets
import { describe, it, expect } from '@ohos/hypium';
import NetworkService from '../../main/ets/service/NetworkService';

export default function NetworkServiceTest() {
describe('NetworkServiceTest', () => {
it('testFetchDataSuccess', 0, async () => {
const networkService = new NetworkService();
const testUrl = 'https://api.example.com/data';

  try {
    const data = await networkService.fetchData(testUrl);
    expect(data).assertNotNull();
    expect(typeof data).assertEqual('object');
  } catch (error) {
    expect.fail(`请求不应该失败: ${error.message}`);
  }
});

it('testFetchDataTimeout', 0, async () => {
  const networkService = new NetworkService();
  const slowUrl = 'https://api.example.com/slow';
  
  networkService.setTimeout(1000); // 1秒超时
  
  try {
    await networkService.fetchData(slowUrl);
    expect.fail('应该抛出超时错误');
  } catch (error) {
    expect(error.message).assertContain('TIMEOUT');
  }
});

it('testBatchRequests', 0, async () => {
  const networkService = new NetworkService();
  const urls = [
    'https://api.example.com/data1',
    'https://api.example.com/data2',
    'https://api.example.com/data3'
  ];
  
  const promises = urls.map(url => networkService.fetchData(url));
  const results = await Promise.all(promises);
  
  expect(results.length).assertEqual(3);
  results.forEach(result => {
    expect(result).assertNotNull();
  });
});

});
}

三、UI测试实战

UI测试确保用户界面的正确性和交互的流畅性。

3.1 UI测试框架配置

UI测试依赖配置:
{
"devDependencies": {
"@ohos/uiTest": "^1.0.0",
"@ohos/accessibility": "^1.0.0"
}
}

基础UI测试示例:
// tests/LoginPageUITest.ets
import { describe, it, expect, by, element } from '@ohos/uiTest';
import { Driver, ON } from '@ohos.uiTest';

export default function LoginPageUITest() {
describe('LoginPageUITest', () => {
let driver: Driver;

before(async () => {
  driver = await Driver.create();
  await driver.delay(1000);
});

after(async () => {
  await driver.delay(500);
  await driver.terminate();
});

it('testLoginPageElements', 0, async () => {
  // 检查页面标题
  const title = await driver.findElement(by.text('用户登录'));
  expect(await title.isDisplayed()).assertTrue();

  // 检查用户名输入框
  const usernameInput = await driver.findElement(by.id('username_input'));
  expect(await usernameInput.isEnabled()).assertTrue();

  // 检查密码输入框
  const passwordInput = await driver.findElement(by.id('password_input'));
  expect(await passwordInput.isEnabled()).assertTrue();

  // 检查登录按钮
  const loginButton = await driver.findElement(by.id('login_button'));
  expect(await loginButton.isEnabled()).assertTrue();
});

it('testSuccessfulLogin', 0, async () => {
  // 输入用户名
  const usernameInput = await driver.findElement(by.id('username_input'));
  await usernameInput.inputText('testuser');

  // 输入密码
  const passwordInput = await driver.findElement(by.id('password_input'));
  await passwordInput.inputText('password123');

  // 点击登录按钮
  const loginButton = await driver.findElement(by.id('login_button'));
  await loginButton.click();

  // 验证跳转结果
  await driver.delay(2000);
  const welcomeText = await driver.findElement(by.text('欢迎回来'));
  expect(await welcomeText.isDisplayed()).assertTrue();
});

it('testLoginValidation', 0, async () => {
  // 测试空用户名
  const usernameInput = await driver.findElement(by.id('username_input'));
  await usernameInput.inputText('');

  const loginButton = await driver.findElement(by.id('login_button'));
  await loginButton.click();

  const errorMessage = await driver.findElement(by.id('error_message'));
  expect(await errorMessage.getText()).assertEqual('用户名不能为空');
});

});
}

3.2 复杂交互测试

测试复杂的用户交互场景:
// tests/ShoppingCartUITest.ets
import { describe, it, expect, by, element } from '@ohos/uiTest';
import { Driver } from '@ohos.uiTest';

export default function ShoppingCartUITest() {
describe('ShoppingCartUITest', () => {
let driver: Driver;

before(async () => {
  driver = await Driver.create();
});

it('testAddToCartFlow', 0, async () => {
  // 浏览商品列表
  const productList = await driver.findElement(by.id('product_list'));
  expect(await productList.isDisplayed()).assertTrue();

  // 选择第一个商品
  const firstProduct = await driver.findElement(by.id('product_0'));
  await firstProduct.click();

  // 添加到购物车
  const addToCartButton = await driver.findElement(by.id('add_to_cart'));
  await addToCartButton.click();

  // 验证购物车数量更新
  const cartBadge = await driver.findElement(by.id('cart_badge'));
  const badgeText = await cartBadge.getText();
  expect(badgeText).assertEqual('1');

  // 进入购物车页面
  const cartIcon = await driver.findElement(by.id('cart_icon'));
  await cartIcon.click();

  // 验证购物车内容
  const cartItem = await driver.findElement(by.id('cart_item_0'));
  expect(await cartItem.isDisplayed()).assertTrue();
});

it('testCheckoutProcess', 0, async () => {
  // 进入结算流程
  const checkoutButton = await driver.findElement(by.id('checkout_button'));
  await checkoutButton.click();

  // 填写收货地址
  const addressInput = await driver.findElement(by.id('address_input'));
  await addressInput.inputText('北京市海淀区测试地址');

  // 选择支付方式
  const paymentMethod = await driver.findElement(by.id('payment_alipay'));
  await paymentMethod.click();

  // 提交订单
  const submitOrderButton = await driver.findElement(by.id('submit_order'));
  await submitOrderButton.click();

  // 验证订单成功
  await driver.delay(3000);
  const successMessage = await driver.findElement(by.text('订单提交成功'));
  expect(await successMessage.isDisplayed()).assertTrue();
});

});
}

四、性能测试与优化

4.1 性能指标测试

监控应用的关键性能指标:
// tests/PerformanceTest.ets
import { describe, it, expect } from '@ohos/hypium';
import { PerformanceMonitor } from '@ohos.performance';

export default function PerformanceTest() {
describe('PerformanceTest', () => {
it('testAppStartupTime', 0, async () => {
const performanceMonitor = new PerformanceMonitor();
const startupTime = await performanceMonitor.measureAppStartup();

  // 冷启动时间应小于500ms
  expect(startupTime.coldStart).assertLessThan(500);
  // 热启动时间应小于200ms
  expect(startupTime.warmStart).assertLessThan(200);
});

it('testMemoryUsage', 0, async () => {
  const memoryInfo = await PerformanceMonitor.getMemoryInfo();
  
  // 内存使用应小于100MB
  expect(memoryInfo.usedMB).assertLessThan(100);
  // 内存泄漏检测
  expect(memoryInfo.leakCount).assertEqual(0);
});

it('testRenderingPerformance', 0, async () => {
  const renderMonitor = new PerformanceMonitor();
  const fps = await renderMonitor.measureFPS();
  
  // 帧率应保持在60FPS以上
  expect(fps.average).assertGreaterThan(60);
  expect(fps.min).assertGreaterThan(55);
});

it('testNetworkPerformance', 0, async () => {
  const networkMonitor = new PerformanceMonitor();
  const responseTime = await networkMonitor.measureNetworkRequest(
    'https://api.example.com/test'
  );
  
  // 网络响应时间应小于1秒
  expect(responseTime).assertLessThan(1000);
});

});
}

4.2 自动化性能优化

实现自动化的性能检测和优化建议:
// utils/PerformanceOptimizer.ets
import performance from '@ohos.performance';

@Component
export class PerformanceOptimizer {
private static readonly PERFORMANCE_THRESHOLDS = {
memory: 100, // MB
fps: 55,
startup: 500, // ms
network: 1000 // ms
};

// 性能健康检查
static async performHealthCheck(): Promise {
const report: PerformanceReport = {
score: 100,
issues: [],
recommendations: []
};

// 内存使用检查
const memoryUsage = await this.checkMemoryUsage();
if (memoryUsage > this.PERFORMANCE_THRESHOLDS.memory) {
  report.score -= 20;
  report.issues.push('内存使用过高');
  report.recommendations.push('优化图片资源加载,使用内存缓存');
}

// 渲染性能检查
const fps = await this.checkFPS();
if (fps < this.PERFORMANCE_THRESHOLDS.fps) {
  report.score -= 15;
  report.issues.push('界面渲染帧率过低');
  report.recommendations.push('减少UI组件嵌套层级,使用懒加载');
}

// 启动时间检查
const startupTime = await this.checkStartupTime();
if (startupTime > this.PERFORMANCE_THRESHOLDS.startup) {
  report.score -= 25;
  report.issues.push('应用启动时间过长');
  report.recommendations.push('延迟加载非关键资源,优化初始化流程');
}

return report;

}

// 生成性能优化报告
static generateOptimizationReport(report: PerformanceReport): string {
let reportText = 性能检测报告\n得分: ${report.score}/100\n\n;

if (report.issues.length > 0) {
  reportText += "发现的问题:\n";
  report.issues.forEach(issue => {
    reportText += `• ${issue}\n`;
  });

  reportText += "\n优化建议:\n";
  report.recommendations.forEach(rec => {
    reportText += `• ${rec}\n`;
  });
} else {
  reportText += "应用性能良好,无需优化";
}

return reportText;

}
}

五、App Gallery Connect发布流程

5.1 应用打包与签名

发布版本构建配置:
// build-profile.json5发布配置
{
"app": {
"signingConfigs": [{
"name": "release",
"certificatePath": "./signature/release.p12",
"certificatePassword": "",
"profilePath": "./signature/release.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "./signature/harmonyCert.p12",
"storePassword": "
"
}],
"products": [{
"name": "default",
"signingConfig": "release",
"compileSdkVersion": "5.0.0",
"compatibleSdkVersion": "5.0.0",
"runtimeOS": "HarmonyOS"
}]
}
}

构建脚本配置:
// scripts/build-release.ets
import { buildManager } from '@ohos/build';

async function buildReleaseVersion(): Promise {
try {
const buildConfig = {
mode: 'release',
target: 'app',
clean: true,
outputPath: './build/outputs/release'
};

console.info('开始构建发布版本...');

const result = await buildManager.build(buildConfig);

if (result.success) {
  console.info('构建成功,文件位置:', result.outputPath);
  
  // 生成构建报告
  await this.generateBuildReport(result);
} else {
  throw new Error(`构建失败: ${result.error}`);
}

} catch (error) {
console.error('构建过程出错:', error);
throw error;
}
}

5.2 应用市场上架

上架前检查清单:
// utils/AppStoreChecklist.ets
@Component
export class AppStoreChecklist {
private static readonly STORE_REQUIREMENTS = {
minSdkVersion: '4.0.0',
maxAppSize: 10, // MB
requiredPermissions: ['ohos.permission.INTERNET'],
privacyPolicyRequired: true,
ageRatingRequired: true,
screenshotRequirements: {
minCount: 3,
maxCount: 10,
requiredResolutions: ['1280x720', '1920x1080']
}
};

// 应用商店合规性检查
static async validateForAppStore(): Promise {
const result: ValidationResult = {
passed: true,
errors: [],
warnings: []
};

// 检查应用大小
const appSize = await this.getAppSize();
if (appSize > this.STORE_REQUIREMENTS.maxAppSize) {
  result.passed = false;
  result.errors.push(`应用大小超过限制: ${appSize}MB > ${this.STORE_REQUIREMENTS.maxAppSize}MB`);
}

// 检查权限声明
const permissionErrors = await this.validatePermissions();
result.errors.push(...permissionErrors);

// 检查隐私政策
if (!await this.hasPrivacyPolicy()) {
  result.passed = false;
  result.errors.push('缺少隐私政策声明');
}

// 检查年龄分级
if (!await this.hasAgeRating()) {
  result.passed = false;
  result.errors.push('缺少年龄分级信息');
}

// 检查截图
const screenshotErrors = await this.validateScreenshots();
result.warnings.push(...screenshotErrors);

return result;

}

// 生成上架准备报告
static generateSubmissionReport(validationResult: ValidationResult): string {
let report = 应用市场上架检查报告\n生成时间: ${new Date().toLocaleString()}\n\n;

if (validationResult.passed) {
  report += "✅ 通过所有强制检查,可以提交上架\n\n";
} else {
  report += "❌ 存在阻止上架的问题:\n";
  validationResult.errors.forEach(error => {
    report += `• ${error}\n`;
  });
}

if (validationResult.warnings.length > 0) {
  report += "\n⚠️ 警告信息(不影响上架):\n";
  validationResult.warnings.forEach(warning => {
    report += `• ${warning}\n`;
  });
}

return report;

}
}

六、持续集成与自动化部署

6.1 CI/CD流水线配置

GitHub Actions配置示例:

.github/workflows/harmonyos-ci.yml

name: HarmonyOS CI/CD

on:
push:
branches: [ main, release/* ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup HarmonyOS Environment
  uses: harmonyos/setup-deveco@v1
  with:
    version: '3.1'
    
- name: Install Dependencies
  run: ohpm install
  
- name: Run Unit Tests
  run: ohpm test
  
- name: Run UI Tests
  run: ohpm test:ui
  
- name: Performance Test
  run: ohpm test:performance

build:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- name: Checkout Code
  uses: actions/checkout@v3
  
- name: Build Release
  run: |
    ohpm build --release
    echo "Build completed successfully"
    
- name: Upload to AppGallery Connect
  uses: harmonyos/upload-agc@v1
  with:
    app-id: ${{ secrets.APP_ID }}
    client-secret: ${{ secrets.CLIENT_SECRET }}
    file: build/outputs/release/app-release.hap

6.2 自动化测试报告

生成详细的测试报告:
// utils/TestReporter.ets
@Component
export class TestReporter {
// 生成单元测试报告
static generateUnitTestReport(testResults: TestResult[]): TestReport {
const report: TestReport = {
totalTests: testResults.length,
passedTests: testResults.filter(r => r.passed).length,
failedTests: testResults.filter(r => !r.passed).length,
successRate: 0,
duration: 0,
detailedResults: []
};

report.successRate = (report.passedTests / report.totalTests) * 100;
report.duration = testResults.reduce((sum, r) => sum + r.duration, 0);

// 详细结果分析
report.detailedResults = testResults.map(result => ({
  name: result.name,
  status: result.passed ? 'PASSED' : 'FAILED',
  duration: result.duration,
  error: result.error || null
}));

return report;

}

// 生成可视化报告
static async generateVisualReport(report: TestReport): Promise {
const chartData = {
type: 'bar',
data: {
labels: ['通过', '失败'],
datasets: [{
label: '测试结果',
data: [report.passedTests, report.failedTests],
backgroundColor: ['#4CAF50', '#F44336']
}]
}
};

return this.renderChart(chartData);

}
}

总结

通过本文的完整测试和上架指南,开发者可以掌握HarmonyOS应用质量保障和发布的全流程。关键要点包括:

  1. 全面测试策略:建立从单元测试到UI测试的完整测试体系
  2. 性能优化:监控关键性能指标,确保应用流畅运行
  3. 合规性检查:遵循应用市场规范,确保顺利上架
  4. 自动化流程:利用CI/CD提高开发效率和质量

成功上架的关键因素:
• 严格的代码质量控制

• 全面的测试覆盖

• 性能优化和用户体验

• 遵循平台规范和最佳实践

通过实施这些策略,开发者可以确保HarmonyOS应用高质量、高效率地交付给最终用户。

需要参加鸿蒙认证的请点击 鸿蒙认证链接

posted @ 2025-10-30 15:42  猫林老师  阅读(16)  评论(0)    收藏  举报