渐进式编程课
鸿蒙 目录
第 28 课2026.08.11

适用场景:保存、提交或支付失败时,后续成功通知、跳转等操作必须停止

第 28 课:Hypium 异步失败交互验证

  • 日期:2026-08-11
  • 课程序号:第 28 课
  • 知识点:验证前置异步操作失败后,不会继续触发成功通知
  • 适用场景:保存、提交或支付失败时,后续成功通知、跳转等操作必须停止

承接上一课:上一课验证“保存完成 → 发送通知”的成功顺序;本课补齐失败路径,验证保存被拒绝时通知不会发生。

核心概念

  • await 遇到被拒绝的 Promise 会立即抛出异常,当前方法中它后面的语句不会继续执行。
  • 失败测试替身应主动返回 Promise.reject(),稳定制造可重复的异常路径。
  • 失败用例只断言业务契约:错误向上传递,且成功通知没有发生;不要在 UI 层伪造成功状态。

最小 ArkTS / Hypium 示例

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

interface DraftService {
  save(content: string): Promise<void>;
}

interface NoticeService {
  send(message: string): void;
}

class DraftPublisher {
  constructor(
    private draftService: DraftService,
    private noticeService: NoticeService
  ) {}

  async publish(content: string): Promise<void> {
    await this.draftService.save(content);
    this.noticeService.send('发布成功');
  }
}

class FailingDraftService implements DraftService {
  save(content: string): Promise<void> {
    return Promise.reject(new Error(`保存失败:${content}`));
  }
}

class SpyNoticeService implements NoticeService {
  callCount: number = 0;

  send(message: string): void {
    this.callCount += 1;
  }
}

export default function draftPublisherFailureTest(): void {
  describe('DraftPublisher failure', () => {
    it('doesNotNotifyWhenSaveFails', 0, async () => {
      const noticeService: SpyNoticeService = new SpyNoticeService();
      const publisher: DraftPublisher = new DraftPublisher(
        new FailingDraftService(),
        noticeService
      );
      let errorMessage: string = '';

      try {
        await publisher.publish('鸿蒙笔记');
      } catch (error) {
        errorMessage = (error as Error).message;
      }

      expect(errorMessage).assertEqual('保存失败:鸿蒙笔记');
      expect(noticeService.callCount).assertEqual(0);
    });
  });
}

FailingDraftService 让保存稳定失败。异常从 publish() 向上传递,同时 send() 位于 await save() 之后,因此调用次数保持为 0。

3~5 分钟练习

临时把 this.noticeService.send('发布成功') 移到 await this.draftService.save(content) 前面,运行测试并观察哪条断言失败;随后恢复正确顺序。

参考答案

通知提前后,即使保存失败,callCount 也已经变为 1,所以“不发送成功通知”的断言失败。正确实现必须先等待保存成功:

ts
async publish(content: string): Promise<void> {
  await this.draftService.save(content);
  this.noticeService.send('发布成功');
}

与上一课的联系

上一课验证成功路径中的先后顺序,本课用同一条调用链验证失败会截断后续交互。合在一起,测试同时覆盖“成功后通知”和“失败不通知”两条关键契约。