如何为Jasmine编写自定义匹配器以校验对象属性值是否在指定范围内
看起来你正在搭建一个Jasmine自定义匹配器来校验对象属性的范围,我来帮你把这个实现补全,还加了一些实用的扩展功能,让匹配器更灵活好用。
完整的
toLieWithin自定义匹配器实现 // 在测试用例的beforeEach中注册匹配器 beforeEach(() => { jasmine.addMatchers({ toLieWithin: function(util: jasmine.MatchersUtil, customEqualityTesters: jasmine.CustomEqualityTester[]): jasmine.CustomMatcher { return { compare: function(actual: Record<string, any>, expected: { min: Record<string, any>, max: Record<string, any>, property?: string }): jasmine.CustomMatcherResult { const result: jasmine.CustomMatcherResult = { pass: false }; // 分两种模式:单个属性校验 / 批量校验所有共同属性 const targetProperty = expected.property; let pass = true; let failureMessage = ''; if (targetProperty) { // 单个属性校验逻辑 const actualValue = actual[targetProperty]; const minValue = expected.min[targetProperty]; const maxValue = expected.max[targetProperty]; // 先检查属性是否存在 if (actualValue === undefined || minValue === undefined || maxValue === undefined) { pass = false; failureMessage = `Missing required property "${targetProperty}" in actual, min, or max object`; } else { // 判断是否在范围内(包含边界) pass = actualValue >= minValue && actualValue <= maxValue; failureMessage = pass ? '' : `Expected ${actualValue} (from actual.${targetProperty}) to lie between ${minValue} (min.${targetProperty}) and ${maxValue} (max.${targetProperty})`; } } else { // 批量校验所有min和max的共同属性 const commonProperties = Object.keys(expected.min).filter(key => key in expected.max); if (commonProperties.length === 0) { pass = false; failureMessage = 'No common properties found between min and max objects'; return { pass, message: failureMessage }; } const failedProps: string[] = []; commonProperties.forEach(key => { const actualVal = actual[key]; const minVal = expected.min[key]; const maxVal = expected.max[key]; if (actualVal === undefined) { failedProps.push(`Actual object missing property "${key}"`); pass = false; } else if (actualVal < minVal || actualVal > maxVal) { failedProps.push(`${actualVal} (actual.${key}) is not between ${minVal} and ${maxVal}`); pass = false; } }); if (!pass) { failureMessage = `The following properties failed range check:\n- ${failedProps.join('\n- ')}`; } } // 处理反向断言(not.toLieWithin) result.pass = pass; result.message = pass ? `Expected ${JSON.stringify(actual)} not to lie within the range defined by min: ${JSON.stringify(expected.min)} and max: ${JSON.stringify(expected.max)}` : failureMessage; return result; } }; } }); });
用法示例
1. 校验单个指定属性
如果你只需要校验对象的某一个属性是否在范围内,可以指定property参数:
const actualUser = { age: 25 }; const ageRangeMin = { age: 20 }; const ageRangeMax = { age: 30 }; // 这个断言会通过 expect(actualUser).toLieWithin({ min: ageRangeMin, max: ageRangeMax, property: 'age' }); // 这个断言会失败,会输出清晰的错误提示 expect(actualUser).toLieWithin({ min: ageRangeMin, max: { age: 24 }, property: 'age' });
2. 批量校验所有共同属性
如果需要一次性校验对象的多个属性是否都在对应范围内,不用指定property,匹配器会自动校验min和max对象的所有共同属性:
const actualProduct = { price: 45, stock: 15 }; const productRangeMin = { price: 40, stock: 10 }; const productRangeMax = { price: 50, stock: 20 }; // 所有属性都符合范围,断言通过 expect(actualProduct).toLieWithin({ min: productRangeMin, max: productRangeMax }); // price属性超出范围,断言失败,会列出所有失败的属性 expect(actualProduct).toLieWithin({ min: productRangeMin, max: { price: 44, stock: 18 } });
关键细节说明
- 边界控制:当前实现包含范围边界(用
>=和<=),如果你需要排除边界,直接把判断条件改成actualValue > minValue && actualValue < maxValue即可。 - 错误提示:匹配器会生成针对性的错误信息,不管是属性缺失还是值超出范围,都能快速定位问题。
- 反向断言支持:完美兼容
not.toLieWithin,会自动生成反向的提示文本。
内容的提问来源于stack exchange,提问作者zelda
相关产品推荐
相关产品推荐

