第 33 课2026.08.18
适用场景:多组输入遵循同一条业务规则,但希望每组数据都有独立用例名,失败时可直接定位具体边界场景
第 33 课:Hypium 参数化测试工厂
- 日期:2026-08-18
- 课程序号:第 33 课
- 知识点:用测试用例工厂为每组边界数据注册独立的
it - 适用场景:多组输入遵循同一条业务规则,但希望每组数据都有独立用例名,失败时可直接定位具体边界场景
承接上一课:上一课用对象工厂集中装配 Fake、Spy 和被测对象;本课把“工厂”思想用于测试用例注册,为每组参数生成一个清晰、独立的行为化用例。
核心概念
- 测试数据只描述用例名、输入和期望结果,不承载业务实现。
- 用例工厂在
describe中逐项调用it,让每组参数成为独立测试,而不是在一个it内循环断言。 - 用例名应包含边界场景,例如
returnsEmptyForZero,这样失败报告能直接指出被破坏的规则。 - 只把 Arrange 的参数差异交给工厂;Act 和 Assert 仍在生成的用例体内清晰可见。
最小 ArkTS / Hypium 示例
ts
import { describe, expect, it } from '@ohos/hypium';
interface UnreadCountCase {
name: string;
input: number;
expected: string;
}
function formatUnreadCount(count: number): string {
if (count <= 0) {
return '';
}
if (count > 99) {
return '99+';
}
return `${count}`;
}
function registerUnreadCountCase(testCase: UnreadCountCase): void {
it(testCase.name, 0, () => {
// Act
const actual: string = formatUnreadCount(testCase.input);
// Assert
expect(actual).assertEqual(testCase.expected);
});
}
export default function unreadCountParameterizedTest(): void {
describe('formatUnreadCount', () => {
const cases: UnreadCountCase[] = [
{ name: 'returnsEmptyForZero', input: 0, expected: '' },
{ name: 'returnsCountAtUpperBoundary', input: 99, expected: '99' },
{ name: 'returns99PlusWhenOverLimit', input: 100, expected: '99+' }
];
cases.forEach((testCase: UnreadCountCase) => {
registerUnreadCountCase(testCase);
});
});
}这里会注册三个独立用例。任何一组失败时,报告会显示对应的行为化名称;其他参数用例仍保持独立。
3~5 分钟练习
给 cases 增加两个独立边界用例:输入 -1 时返回空字符串,输入 1 时返回 1。用行为化名称描述结果,不修改 formatUnreadCount()。
参考答案
ts
const cases: UnreadCountCase[] = [
{ name: 'returnsEmptyForNegativeCount', input: -1, expected: '' },
{ name: 'returnsEmptyForZero', input: 0, expected: '' },
{ name: 'returnsOneForSingleUnreadItem', input: 1, expected: '1' },
{ name: 'returnsCountAtUpperBoundary', input: 99, expected: '99' },
{ name: 'returns99PlusWhenOverLimit', input: 100, expected: '99+' }
];现有业务实现已经覆盖这两个边界,无需修改生产代码;重新运行测试即可看到五个独立用例。
与上一课的联系
上一课的对象工厂减少依赖装配的重复代码;本课的用例工厂减少相同测试结构的重复代码。两者都只抽取稳定结构,不隐藏每个用例的差异条件和行为契约。