0
点赞
收藏
分享

微信扫一扫

HarmonyOS之单元测试与自动化测试:Hypium框架使用指南

本文将深入探讨HarmonyOS中的单元测试与自动化测试实践,重点介绍Hypium测试框架的核心功能和使用方法,帮助您构建完善的测试体系。

1. Hypium测试框架概述

Hypium是HarmonyOS官方提供的一体化测试框架,集成了单元测试、UI测试和性能测试能力,为开发者提供完整的测试解决方案。

1.1 框架核心特性

  • 多测试类型支持:单元测试、UI自动化测试、性能测试、分布式测试
  • 丰富的断言库:提供多种断言方法验证测试结果
  • Mock能力:支持函数和对象的模拟,隔离测试环境
  • 数据驱动测试:通过外部数据文件驱动测试用例执行
  • 分布式测试支持:专为HarmonyOS多设备协同场景设计

1.2 环境配置与依赖

在项目的package.json中添加Hypium依赖:

{
  "dependencies": {
    "@ohos/hypium": "1.0.6"
  }
}

在需要运行的测试模块下的ohosTest目录中配置测试依赖:

// ohosTest模块下的package.json
{
  "dependencies": {
    "decc.test": "^1.0.0",
    "hypium": "^1.0.0"
  }
}

2. 单元测试实践

单元测试是测试金字塔的基础,专注于验证单个函数、方法或组件的正确性。

2.1 基础单元测试编写

// 计算器类 - 被测试代码
export class Calculator {
  // 加法运算
  add(a: number, b: number): number {
    return a + b;
  }

  // 减法运算
  subtract(a: number, b: number): number {
    return a - b;
  }

  // 乘法运算
  multiply(a: number, b: number): number {
    return a * b;
  }

  // 除法运算
  divide(a: number, b: number): number {
    if (b === 0) {
      throw new Error('Division by zero is not allowed');
    }
    return a / b;
  }

  // 复杂计算:百分比
  calculatePercentage(value: number, total: number): number {
    if (total === 0) {
      throw new Error('Total cannot be zero for percentage calculation');
    }
    return (value / total) * 100;
  }
}
// Calculator.test.ts - 单元测试
import { describe, it, expect, beforeAll, afterAll } from '@ohos/hypium';
import { Calculator } from '../src/main/ets/utils/Calculator';

describe('Calculator Tests', () => {
  let calculator: Calculator;

  // 测试前置操作
  beforeAll(() => {
    calculator = new Calculator();
    console.info('Calculator instance created');
  });

  // 测试后置清理
  afterAll(() => {
    console.info('Calculator tests completed');
  });

  // 加法测试
  it('should_add_two_numbers_correctly', 0, () => {
    const result = calculator.add(2, 3);
    expect(result).assertEqual(5);
  });

  // 减法测试
  it('should_subtract_two_numbers_correctly', 0, () => {
    const result = calculator.subtract(5, 3);
    expect(result).assertEqual(2);
  });

  // 乘法测试
  it('should_multiply_two_numbers_correctly', 0, () => {
    const result = calculator.multiply(4, 3);
    expect(result).assertEqual(12);
  });

  // 除法测试
  it('should_divide_two_numbers_correctly', 0, () => {
    const result = calculator.divide(10, 2);
    expect(result).assertEqual(5);
  });

  // 除零异常测试
  it('should_throw_error_when_dividing_by_zero', 0, () => {
    try {
      calculator.divide(10, 0);
      // 如果执行到这里说明测试失败
      expect(true).assertFalse(); // 强制测试失败
    } catch (error) {
      expect(error.message).assertEqual('Division by zero is not allowed');
    }
  });

  // 百分比计算测试
  it('should_calculate_percentage_correctly', 0, () => {
    const result = calculator.calculatePercentage(25, 100);
    expect(result).assertEqual(25);
  });

  // 边界值测试
  it('should_handle_zero_value_in_percentage_calculation', 0, () => {
    const result = calculator.calculatePercentage(0, 100);
    expect(result).assertEqual(0);
  });

  // 异常情况测试
  it('should_throw_error_for_zero_total_in_percentage', 0, () => {
    try {
      calculator.calculatePercentage(50, 0);
      expect(true).assertFalse();
    } catch (error) {
      expect(error.message).assertEqual('Total cannot be zero for percentage calculation');
    }
  });
});

2.2 异步操作测试

// 数据服务类 - 包含异步操作
export class DataService {
  // 模拟异步数据获取
  async fetchData(url: string): Promise<any> {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (url.includes('error')) {
          reject(new Error('Network error'));
        } else {
          resolve({ data: 'mock data', status: 200 });
        }
      }, 100);
    });
  }

  // 处理多个异步操作
  async processMultipleRequests(urls: string[]): Promise<any[]> {
    const results: any[] = [];
    for (const url of urls) {
      try {
        const result = await this.fetchData(url);
        results.push(result);
      } catch (error) {
        results.push({ error: error.message });
      }
    }
    return results;
  }
}
// DataService.test.ts - 异步测试
import { describe, it, expect, beforeEach } from '@ohos/hypium';
import { DataService } from '../src/main/ets/services/DataService';

describe('DataService Tests', () => {
  let dataService: DataService;

  beforeEach(() => {
    dataService = new DataService();
  });

  // 成功异步操作测试
  it('should_fetch_data_successfully', 0, async () => {
    const result = await dataService.fetchData('https://api.example.com/data');
    expect(result.status).assertEqual(200);
    expect(result.data).assertEqual('mock data');
  });

  // 异步操作失败测试
  it('should_handle_network_error', 0, async () => {
    try {
      await dataService.fetchData('https://api.example.com/error');
      expect(true).assertFalse(); // 不应该执行到这里
    } catch (error) {
      expect(error.message).assertEqual('Network error');
    }
  });

  // 多个异步操作测试
  it('should_process_multiple_requests_correctly', 0, async () => {
    const urls = [
      'https://api.example.com/data1',
      'https://api.example.com/data2',
      'https://api.example.com/error' // 其中一个会失败
    ];

    const results = await dataService.processMultipleRequests(urls);
    
    expect(results.length).assertEqual(3);
    expect(results[0].status).assertEqual(200);
    expect(results[2].error).assertEqual('Network error');
  });

  // 超时测试
  it('should_complete_within_time_limit', 0, async () => {
    const startTime = Date.now();
    await dataService.fetchData('https://api.example.com/data');
    const duration = Date.now() - startTime;
    
    expect(duration).assertLess(200); // 应该在200ms内完成
  });
});

3. Mock与测试隔离

使用Mock技术隔离外部依赖,确保测试的纯粹性和可重复性。

3.1 函数Mock示例

// 用户服务类
export class UserService {
  private apiUrl: string = 'https://api.example.com/users';

  // 获取用户信息
  async getUserInfo(userId: string): Promise<any> {
    const response = await fetch(`${this.apiUrl}/${userId}`);
    return response.json();
  }

  // 验证用户权限
  hasPermission(user: any, permission: string): boolean {
    return user.permissions.includes(permission);
  }
}
// UserService.test.ts - Mock测试
import { describe, it, expect, beforeEach, mock } from '@ohos/hypium';
import { UserService } from '../src/main/ets/services/UserService';

describe('UserService Tests', () => {
  let userService: UserService;

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

  // Mock fetch函数
  it('should_get_user_info_using_mock_fetch', 0, async () => {
    // 模拟fetch函数
    const mockFetch = mock(global, 'fetch');
    const mockUser = { id: '1', name: 'John Doe', permissions: ['read', 'write'] };

    // 设置mock返回值
    mockFetch.mockImplementation(() => 
      Promise.resolve({
        json: () => Promise.resolve(mockUser)
      })
    );

    const userInfo = await userService.getUserInfo('1');
    
    expect(userInfo.id).assertEqual('1');
    expect(userInfo.name).assertEqual('John Doe');
    expect(mockFetch).toHaveBeenCalledWith('https://api.example.com/users/1');

    // 恢复原始实现
    mockFetch.restore();
  });

  // 权限验证测试
  it('should_check_user_permissions_correctly', 0, () => {
    const user = {
      id: '1',
      name: 'Test User',
      permissions: ['read', 'write', 'delete']
    };

    expect(userService.hasPermission(user, 'read')).assertTrue();
    expect(userService.hasPermission(user, 'write')).assertTrue();
    expect(userService.hasPermission(user, 'admin')).assertFalse();
  });

  // 错误处理测试
  it('should_handle_api_errors', 0, async () => {
    const mockFetch = mock(global, 'fetch');
    mockFetch.mockImplementation(() => 
      Promise.reject(new Error('API unavailable'))
    );

    try {
      await userService.getUserInfo('1');
      expect(true).assertFalse();
    } catch (error) {
      expect(error.message).assertEqual('API unavailable');
    }

    mockFetch.restore();
  });
});

3.2 复杂对象Mock

// 数据库服务类
export class DatabaseService {
  private connection: any;

  constructor(connection: any) {
    this.connection = connection;
  }

  async query(sql: string, params: any[] = []): Promise<any[]> {
    return this.connection.execute(sql, params);
  }

  async getUserById(id: string): Promise<any> {
    const result = await this.query('SELECT * FROM users WHERE id = ?', [id]);
    return result[0];
  }
}
// DatabaseService.test.ts - 复杂Mock
import { describe, it, expect, beforeEach, mock } from '@ohos/hypium';
import { DatabaseService } from '../src/main/ets/services/DatabaseService';

describe('DatabaseService Tests', () => {
  let mockConnection: any;
  let dbService: DatabaseService;

  beforeEach(() => {
    // 创建模拟数据库连接
    mockConnection = {
      execute: mock().mockImplementation((sql, params) => {
        if (sql.includes('SELECT')) {
          return Promise.resolve([{ id: params[0], name: 'Mock User' }]);
        }
        return Promise.resolve([]);
      })
    };

    dbService = new DatabaseService(mockConnection);
  });

  it('should_execute_query_with_mock_connection', 0, async () => {
    const result = await dbService.query('SELECT * FROM users WHERE id = ?', ['1']);
    
    expect(result.length).assertEqual(1);
    expect(result[0].id).assertEqual('1');
    expect(result[0].name).assertEqual('Mock User');
    expect(mockConnection.execute).toHaveBeenCalledWith(
      'SELECT * FROM users WHERE id = ?', 
      ['1']
    );
  });

  it('should_get_user_by_id', 0, async () => {
    const user = await dbService.getUserById('123');
    
    expect(user.id).assertEqual('123');
    expect(user.name).assertEqual('Mock User');
  });

  it('should_handle_empty_results', 0, async () => {
    // 重写mock实现返回空数组
    mockConnection.execute.mockImplementation(() => Promise.resolve([]));
    
    const user = await dbService.getUserById('999');
    expect(user).assertUndefined();
  });
});

4. UI自动化测试

UI测试验证用户界面的交互和显示是否正确。

4.1 基础UI组件测试

// 登录组件
@Component
export struct LoginComponent {
  @State username: string = '';
  @State password: string = '';
  @State errorMessage: string = '';
  @State isLoading: boolean = false;

  // 登录处理
  async handleLogin() {
    if (!this.username || !this.password) {
      this.errorMessage = '用户名和密码不能为空';
      return;
    }

    this.isLoading = true;
    this.errorMessage = '';

    try {
      // 模拟登录API调用
      await this.loginAPI(this.username, this.password);
      // 登录成功处理...
    } catch (error) {
      this.errorMessage = '登录失败,请检查凭证';
    } finally {
      this.isLoading = false;
    }
  }

  private async loginAPI(username: string, password: string): Promise<void> {
    // 模拟API调用
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (username === 'admin' && password === 'password') {
          resolve();
        } else {
          reject(new Error('Invalid credentials'));
        }
      }, 1000);
    });
  }

  build() {
    Column() {
      TextInput({ placeholder: '用户名' })
        .onChange((value: string) => {
          this.username = value;
        })
        .width('80%')
        .margin(10)

      TextInput({ placeholder: '密码', type: InputType.Password })
        .onChange((value: string) => {
          this.password = value;
        })
        .width('80%')
        .margin(10)

      if (this.errorMessage) {
        Text(this.errorMessage)
          .fontColor(Color.Red)
          .margin(10)
      }

      if (this.isLoading) {
        LoadingIndicator()
          .margin(10)
      } else {
        Button('登录', () => {
          this.handleLogin();
        })
        .width('80%')
        .margin(10)
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
// LoginComponent.test.ts - UI测试
import { describe, it, expect, beforeEach } from '@ohos/hypium';
import { LoginComponent } from '../src/main/ets/components/LoginComponent';
import { Driver, ON } from '@kit.TestKit';

describe('LoginComponent UI Tests', () => {
  let driver: Driver;
  let loginComponent: LoginComponent;

  beforeEach(() => {
    driver = Driver.create();
    loginComponent = new LoginComponent();
  });

  it('should_display_error_when_fields_empty', 0, async () => {
    // 直接测试组件方法
    await loginComponent.handleLogin();
    
    expect(loginComponent.errorMessage).assertEqual('用户名和密码不能为空');
  });

  it('should_show_loading_indicator_during_login', 0, async () => {
    loginComponent.username = 'admin';
    loginComponent.password = 'password';

    // 启动登录过程
    const loginPromise = loginComponent.handleLogin();
    
    // 检查加载状态
    expect(loginComponent.isLoading).assertTrue();
    
    // 等待登录完成
    await loginPromise;
    expect(loginComponent.isLoading).assertFalse();
  });

  it('should_handle_successful_login', 0, async () => {
    loginComponent.username = 'admin';
    loginComponent.password = 'password';

    await loginComponent.handleLogin();
    
    expect(loginComponent.errorMessage).assertEqual('');
  });

  it('should_handle_failed_login', 0, async () => {
    loginComponent.username = 'wrong';
    loginComponent.password = 'wrong';

    await loginComponent.handleLogin();
    
    expect(loginComponent.errorMessage).assertEqual('登录失败,请检查凭证');
  });
});

4.2 完整页面UI测试

// 主页测试示例
import { describe, it, expect, beforeAll } from '@ohos/hypium';
import { Driver, ON, device } from '@kit.TestKit';

describe('HomePage UI Tests', () => {
  let driver: Driver;

  beforeAll(async () => {
    driver = Driver.create();
    // 启动应用
    await device.launchApp({ bundleName: 'com.example.app' });
    await driver.delayMs(1000); // 等待应用加载
  });

  it('should_display_welcome_message', 0, async () => {
    const welcomeText = await driver.findComponent(ON.text('欢迎使用'));
    expect(await welcomeText.isDisplayed()).assertTrue();
  });

  it('should_navigate_to_settings', 0, async () => {
    // 查找设置按钮并点击
    const settingsButton = await driver.findComponent(ON.id('settings_button'));
    await settingsButton.click();
    await driver.delayMs(500);

    // 验证是否跳转到设置页面
    const settingsTitle = await driver.findComponent(ON.text('设置'));
    expect(await settingsTitle.isDisplayed()).assertTrue();
  });

  it('should_handle_form_submission', 0, async () => {
    // 在表单中输入文本
    const nameInput = await driver.findComponent(ON.id('name_input'));
    await nameInput.typeText('Test User');

    const emailInput = await driver.findComponent(ON.id('email_input'));
    await emailInput.typeText('test@example.com');

    // 提交表单
    const submitButton = await driver.findComponent(ON.id('submit_button'));
    await submitButton.click();
    await driver.delayMs(1000);

    // 验证提交结果
    const successMessage = await driver.findComponent(ON.text('提交成功'));
    expect(await successMessage.isDisplayed()).assertTrue();
  });

  it('should_display_list_items_correctly', 0, async () => {
    // 滚动查找列表项
    const listItems = await driver.findComponents(ON.className('list_item'));
    expect(listItems.length).assertLarger(0);

    // 验证第一个列表项的内容
    const firstItem = listItems[0];
    const itemText = await firstItem.getText();
    expect(itemText).assertContain('Item');
  });
});

5. 数据驱动测试

数据驱动测试允许使用外部数据文件来参数化测试用例。

5.1 数据文件配置

创建test/data.json数据文件:

{
  "suites": [
    {
      "describe": "LoginTestSuite",
      "params": {
        "testEnvironment": "staging"
      },
      "items": [
        {
          "it": "test_login_scenarios",
          "stress": 3,
          "params": [
            {
              "username": "admin",
              "password": "password",
              "expectedSuccess": true,
              "description": "Valid credentials"
            },
            {
              "username": "user",
              "password": "wrong",
              "expectedSuccess": false,
              "description": "Invalid password"
            },
            {
              "username": "",
              "password": "password",
              "expectedSuccess": false,
              "description": "Empty username"
            },
            {
              "username": "admin",
              "password": "",
              "expectedSuccess": false,
              "description": "Empty password"
            }
          ]
        }
      ]
    }
  ]
}

5.2 数据驱动测试用例

// LoginDataDriven.test.ts
import { describe, it, expect } from '@ohos/hypium';
import { LoginComponent } from '../src/main/ets/components/LoginComponent';

// 从数据文件导入测试数据
const testData = require('../test/data.json');

describe('LoginDataDrivenTests', () => {
  const loginScenarios = testData.suites[0].items[0].params;

  loginScenarios.forEach((scenario: any, index: number) => {
    it(`login_scenario_${index + 1}: ${scenario.description}`, 0, async () => {
      const loginComponent = new LoginComponent();
      
      // 设置测试数据
      loginComponent.username = scenario.username;
      loginComponent.password = scenario.password;

      try {
        await loginComponent.handleLogin();
        
        if (scenario.expectedSuccess) {
          expect(loginComponent.errorMessage).assertEqual('');
        } else {
          expect(loginComponent.errorMessage).assertNotEqual('');
        }
      } catch (error) {
        // 处理意外错误
        expect(error.message).assertEqual('Unexpected test error');
      }
    });
  });

  // 压力测试:多次执行同一测试用例
  it('login_stress_test', 0, async () => {
    const loginComponent = new LoginComponent();
    const validScenario = loginScenarios[0];

    for (let i = 0; i < 10; i++) {
      loginComponent.username = validScenario.username;
      loginComponent.password = validScenario.password;

      await loginComponent.handleLogin();
      expect(loginComponent.errorMessage).assertEqual('');
    }
  });
});

6. 性能测试

性能测试确保应用在各种条件下都能保持良好的性能表现。

6.1 基础性能测试

// PerformanceTests.test.ts
import { describe, it, expect, perf } from '@ohos/hypium';
import { Calculator } from '../src/main/ets/utils/Calculator';
import { HeavyOperationService } from '../src/main/ets/services/HeavyOperationService';

describe('Performance Tests', () => {
  let calculator: Calculator;
  let heavyService: HeavyOperationService;

  beforeAll(() => {
    calculator = new Calculator();
    heavyService = new HeavyOperationService();
  });

  it('should_calculate_quickly', 0, async () => {
    const result = await perf.measureTime(() => {
      // 执行1000次计算操作
      for (let i = 0; i < 1000; i++) {
        calculator.add(i, i * 2);
        calculator.multiply(i, 3);
      }
    });

    expect(result.totalTime).assertLess(50); // 应在50ms内完成
  });

  it('should_maintain_low_memory_usage', 0, async () => {
    const memoryUsage = await perf.measureMemory(() => {
      // 创建大量临时对象
      const tempArray = [];
      for (let i = 0; i < 10000; i++) {
        tempArray.push({ index: i, data: 'test'.repeat(10) });
      }
      return tempArray.length;
    });

    expect(memoryUsage.peakBytes).assertLess(10 * 1024 * 1024); // 峰值内存应小于10MB
  });

  it('should_handle_heavy_operations_efficiently', 0, async () => {
    const performanceResult = await perf.measure(() => {
      return heavyService.processLargeData(10000);
    });

    expect(performanceResult.time).assertLess(1000); // 操作时间应小于1秒
    expect(performanceResult.memory).assertLess(5 * 1024 * 1024); // 内存使用应小于5MB
  });

  it('should_maintain_high_fps_during_ui_operations', 0, async () => {
    const fpsResult = await perf.measureFPS(async () => {
      // 模拟UI渲染操作
      for (let i = 0; i < 60; i++) {
        await heavyService.simulateUIRender();
        await perf.delayMs(16); // 模拟60FPS的帧间隔
      }
    });

    expect(fpsResult.avgFPS).assertLarger(55); // 平均FPS应高于55
    expect(fpsResult.minFPS).assertLarger(45); // 最低FPS应高于45
  });
});

6.2 高级性能监控

// AdvancedPerformanceMonitor.test.ts
import { describe, it, expect, perf, mock } from '@ohos/hypium';
import { PerformanceMonitor } from '../src/main/ets/utils/PerformanceMonitor';

describe('Advanced Performance Monitoring', () => {
  it('should_monitor_cpu_usage', 0, async () => {
    const cpuUsage = await perf.measureCPU(() => {
      // CPU密集型操作
      let result = 0;
      for (let i = 0; i < 1000000; i++) {
        result += Math.sqrt(i) * Math.cos(i);
      }
      return result;
    });

    expect(cpuUsage.percentage).assertLess(80); // CPU使用率应低于80%
  });

  it('should_detect_memory_leaks', 0, async () => {
    const memoryResults = [];
    
    // 多次执行相同操作,检查内存增长
    for (let i = 0; i < 10; i++) {
      const result = await perf.measureMemory(() => {
        // 模拟可能的内存泄漏操作
        const data = new Array(1000).fill('test data');
        return data.length;
      });
      
      memoryResults.push(result.peakBytes);
      await perf.delayMs(100);
    }

    // 检查内存是否稳定增长(可能的内存泄漏)
    const memoryGrowth = memoryResults[memoryResults.length - 1] - memoryResults[0];
    expect(memoryGrowth).assertLess(1024 * 1024); // 内存增长应小于1MB
  });

  it('should_measure_network_performance', 0, async () => {
    const networkMetrics = await perf.measureNetwork(async () => {
      // 模拟网络请求
      await perf.delayMs(100); // 模拟网络延迟
      return { status: 200, data: 'response' };
    });

    expect(networkMetrics.latency).assertLess(200); // 延迟应小于200ms
    expect(networkMetrics.success).assertTrue(); // 请求应成功
  });
});

7. 持续集成与自动化执行

将测试集成到CI/CD流水线中,实现自动化测试执行。

7.1 CI/CD配置示例

// Jenkinsfile 或 GitHub Actions 配置示例
pipeline {
  agent any
  stages {
    stage('Checkout') {
      steps {
        git branch: 'main', 
        url: 'https://github.com/your-repo/your-harmonyos-app.git'
      }
    }
    
    stage('Build') {
      steps {
        script {
          sh 'npm install'
          sh 'npm run build'
        }
      }
    }
    
    stage('Test') {
      steps {
        script {
          // 运行单元测试
          sh 'npm run test:unit -- --coverage'
          
          // 运行UI测试
          sh 'npm run test:ui -- --device=emulator-5554'
          
          // 运行性能测试
          sh 'npm run test:perf'
        }
      }
    }
    
    stage('Report') {
      steps {
        script {
          // 生成测试报告
          sh 'npm run test:report'
          
          // 发布测试结果
          publishHTML target: [
            allowMissing: true,
            alwaysLinkToLastBuild: true,
            keepAll: true,
            reportDir: 'test-reports',
            reportFiles: 'index.html',
            reportName: 'Test Results'
          ]
        }
      }
    }
  }
  
  post {
    always {
      // 清理操作
      cleanWs()
    }
  }
}

7.2 测试脚本配置

package.json中配置测试脚本:

{
  "scripts": {
    "test:unit": "hypium test --type unit --coverage",
    "test:ui": "hypium test --type ui --device emulator-5554",
    "test:perf": "hypium test --type performance",
    "test:all": "npm run test:unit && npm run test:ui && npm run test:perf",
    "test:report": "hypium report --format html --output test-reports/",
    "test:ci": "npm run test:all -- --ci --headless"
  }
}

8. 测试报告与结果分析

生成详细的测试报告,帮助分析测试结果和改进代码质量。

8.1 测试报告生成

// ReportGenerator.ts
import { writeFile, mkdir } from '@ohos.fileio';
import { TestResults, TestSuiteResult, TestCaseResult } from '@ohos/hypium/reporter';

export class TestReportGenerator {
  async generateHTMLReport(results: TestResults, outputPath: string): Promise<void> {
    const reportContent = this.buildHTMLContent(results);
    await this.ensureDirectoryExists(outputPath);
    await writeFile(`${outputPath}/index.html`, reportContent);
  }

  private buildHTMLContent(results: TestResults): string {
    return `
<!DOCTYPE html>
<html>
<head>
    <title>Test Execution Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .summary { background: #f5f5f5; padding: 15px; border-radius: 5px; }
        .test-suite { margin: 10px 0; }
        .test-case { padding: 5px; margin: 2px; }
        .passed { background: #d4edda; }
        .failed { background: #f8d7da; }
        .skipped { background: #fff3cd; }
    </style>
</head>
<body>
    <h1>Test Execution Report</h1>
    
    <div class="summary">
        <h2>Summary</h2>
        <p>Total Tests: ${results.totalTests}</p>
        <p>Passed: ${results.passed}</p>
        <p>Failed: ${results.failed}</p>
        <p>Skipped: ${results.skipped}</p>
        <p>Success Rate: ${((results.passed / results.totalTests) * 100).toFixed(2)}%</p>
    </div>

    ${this.buildTestSuitesContent(results.suites)}
</body>
</html>`;
  }

  private buildTestSuitesContent(suites: TestSuiteResult[]): string {
    return suites.map(suite => `
      <div class="test-suite">
          <h3>${suite.name}</h3>
          ${suite.testCases.map(testCase => `
            <div class="test-case ${testCase.status}">
                <strong>${testCase.name}</strong>: ${testCase.status}
                ${testCase.error ? `<br><em>Error: ${testCase.error}</em>` : ''}
                ${testCase.duration ? `<br>Duration: ${testCase.duration}ms` : ''}
            </div>
          `).join('')}
      </div>
    `).join('');
  }

  private async ensureDirectoryExists(path: string): Promise<void> {
    try {
      await mkdir(path, { recursive: true });
    } catch (error) {
      console.warn(`Directory creation failed: ${error.message}`);
    }
  }
}

9. 最佳实践与建议

9.1 测试策略建议

  1. 测试金字塔遵循:70%单元测试,20%集成测试,10%UI测试
  2. 及时测试:编写代码的同时编写测试用例
  3. 覆盖率目标:关键业务代码达到80%以上覆盖率
  4. Mock适度使用:只Mock外部依赖,避免过度Mock
  5. 定期重构测试:保持测试代码的整洁和可维护性

9.2 常见问题解决

// 常见测试问题解决方案
import { describe, it, expect } from '@ohos/hypium';

describe('Troubleshooting Guide', () => {
  // 1. 异步测试超时问题
  it('should_handle_async_timeouts', 0, async () => {
    // 增加超时时间
    this.timeout(5000); // 5秒超时
    
    await someAsyncOperation();
    expect(true).assertTrue();
  });

  // 2. 测试依赖顺序问题
  it('should_run_independently', 0, () => {
    // 确保每个测试都是独立的
    // 使用beforeEach/afterEach重置状态
  });

  // 3. 浮动点数比较
  it('should_compare_floating_point_numbers', 0, () => {
    const result = 0.1 + 0.2;
    // 使用近似比较而不是精确相等
    expect(result).assertCloseTo(0.3, 0.0001);
  });

  // 4. 测试随机性
  it('should_handle_randomness', 0, () => {
    // 设置随机种子或Mock随机数生成器
    mock(Math, 'random').mockReturnValue(0.5);
    
    const randomValue = Math.random();
    expect(randomValue).assertEqual(0.5);
  });
});

通过本指南,您应该能够建立完整的HarmonyOS应用测试体系,从单元测试到UI自动化测试,从性能测试到持续集成。记住良好的测试实践是高质量软件开发的基石。

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

举报

相关推荐

0 条评论