第 25 课2026.08.06
适用场景:被测对象依赖网络、数据库等外部服务,希望单元测试快速、稳定且不访问真实环境
第 25 课:Hypium 测试替身与依赖注入
- 日期:2026-08-06
- 课程序号:第 25 课
- 知识点:用 Fake 服务替换真实依赖,并验证调用参数与返回结果
- 适用场景:被测对象依赖网络、数据库等外部服务,希望单元测试快速、稳定且不访问真实环境
承接上一课:数据表驱动测试解决了“同一规则如何覆盖多组输入”;本课解决“被测逻辑依赖外部服务时如何隔离测试”。
核心概念
- 依赖注入:被测对象不在内部创建具体服务,而是从构造函数接收接口实现。
- Fake(测试替身):实现同一接口,返回可控数据,并记录收到的参数。
- 测试既要断言业务结果,也可断言依赖是否收到正确参数;无需发起真实请求。
最小 ArkTS / Hypium 示例
ts
import { describe, expect, it } from '@ohos/hypium';
interface UserService {
queryName(userId: number): Promise<string>;
}
class UserProfile {
constructor(private userService: UserService) {}
async getGreeting(userId: number): Promise<string> {
const name: string = await this.userService.queryName(userId);
return `你好,${name}`;
}
}
class FakeUserService implements UserService {
lastUserId: number = -1;
queryName(userId: number): Promise<string> {
this.lastUserId = userId;
return Promise.resolve('小鸿');
}
}
export default function userProfileTest(): void {
describe('UserProfile', () => {
it('usesUserIdAndReturnsGreeting', 0, async () => {
const fakeService: FakeUserService = new FakeUserService();
const profile: UserProfile = new UserProfile(fakeService);
const greeting: string = await profile.getGreeting(1001);
expect(fakeService.lastUserId).assertEqual(1001);
expect(greeting).assertEqual('你好,小鸿');
});
});
}UserProfile 只依赖 UserService 接口。生产环境可以注入真实实现,测试中则注入 FakeUserService,因此测试结果完全可控。
3~5 分钟练习
让 FakeUserService 的返回姓名可配置:通过构造函数接收 name,然后在测试中传入 小明,验证结果为 你好,小明。
参考答案
ts
class FakeUserService implements UserService {
lastUserId: number = -1;
constructor(private name: string) {}
queryName(userId: number): Promise<string> {
this.lastUserId = userId;
return Promise.resolve(this.name);
}
}
const fakeService: FakeUserService = new FakeUserService('小明');
const profile: UserProfile = new UserProfile(fakeService);
const greeting: string = await profile.getGreeting(1001);
expect(greeting).assertEqual('你好,小明');与上一课的联系
上一课用数据表控制多组输入与期望值;本课进一步用 Fake 控制外部依赖的行为。二者可以组合:把不同 Fake 返回值写入数据表,集中验证多种服务响应下的业务结果。