第 26 课2026.08.07
适用场景:业务结果相同,但仍需确认保存、上报或通知等依赖是否被调用了正确次数
第 26 课:Hypium 交互验证与调用次数
- 日期:2026-08-07
- 课程序号:第 26 课
- 知识点:用 Spy 测试替身记录依赖调用次数,验证关键交互契约
- 适用场景:业务结果相同,但仍需确认保存、上报或通知等依赖是否被调用了正确次数
承接上一课:上一课用 Fake 服务控制返回值并记录参数;本课让测试替身继续记录调用次数,验证被测对象与依赖之间的交互契约。
核心概念
- Spy(间谍测试替身):在提供可控行为的同时,记录方法被调用的次数和参数。
- 调用次数属于交互契约。例如“一次用户操作只能保存一次”值得断言;内部辅助函数调用了几次通常属于实现细节,不应写进测试。
- 每个测试都创建新的 Spy,避免不同用例共享计数而相互影响。
最小 ArkTS / Hypium 示例
ts
import { describe, expect, it } from '@ohos/hypium';
interface FavoriteService {
save(stockCode: string): Promise<void>;
}
class FavoriteManager {
constructor(private favoriteService: FavoriteService) {}
async add(stockCode: string): Promise<string> {
await this.favoriteService.save(stockCode);
return '收藏成功';
}
}
class SpyFavoriteService implements FavoriteService {
callCount: number = 0;
lastStockCode: string = '';
save(stockCode: string): Promise<void> {
this.callCount += 1;
this.lastStockCode = stockCode;
return Promise.resolve();
}
}
export default function favoriteManagerTest(): void {
describe('FavoriteManager', () => {
it('savesExactlyOnce', 0, async () => {
const spyService: SpyFavoriteService = new SpyFavoriteService();
const manager: FavoriteManager = new FavoriteManager(spyService);
const result: string = await manager.add('600000');
expect(spyService.callCount).assertEqual(1);
expect(spyService.lastStockCode).assertEqual('600000');
expect(result).assertEqual('收藏成功');
});
});
}这里断言了三个对外可观察结果:保存恰好发生一次、参数正确、业务结果正确。测试没有关心 FavoriteManager 内部如何组织代码。
3~5 分钟练习
给 FavoriteManager 增加 addTwiceForDemo(stockCode):连续调用两次 save()。补一个测试,验证 Spy 的 callCount 为 2,且最后一次参数仍是传入的股票代码。
参考答案
ts
async addTwiceForDemo(stockCode: string): Promise<void> {
await this.favoriteService.save(stockCode);
await this.favoriteService.save(stockCode);
}
it('savesTwiceForDemo', 0, async () => {
const spyService: SpyFavoriteService = new SpyFavoriteService();
const manager: FavoriteManager = new FavoriteManager(spyService);
await manager.addTwiceForDemo('600000');
expect(spyService.callCount).assertEqual(2);
expect(spyService.lastStockCode).assertEqual('600000');
});与上一课的联系
上一课的 Fake 主要回答“依赖返回什么、被测逻辑输出什么”;本课的 Spy 进一步回答“依赖是否按契约被调用”。同一个测试替身可以同时承担可控返回值和调用记录,但断言应只覆盖真正重要的外部交互。