季节判断函数测试失败:伪造Date对象场景未抛出指定错误
问题:伪造Date对象导致getSeason函数校验失效
我实现了一个根据输入日期判断季节的getSeason函数,大部分测试用例都能通过,但在一个伪造Date对象的测试用例中失败了。该测试用例创建了一个设置了Date原型、Symbol.toStringTag为'Date'的伪造对象,要求函数抛出"Invalid date!"错误,但当前函数未满足要求,返回actual: false; expected: true。
编写的函数代码
function getSeason(date) { const isValidDate = (d) => { return d instanceof Date && !isNaN(d); }; let season = ""; if (date === undefined) return "Unable to determine the time of year!"; if (!isValidDate(date)) throw new Error("Invalid date!"); const springStart = new Date(date.getFullYear(), 2, 1); const summerStart = new Date(date.getFullYear(), 5, 1); const autumnStart = new Date(date.getFullYear(), 8, 1); const winterStart = new Date(date.getFullYear(), 11, 1); if (date >= springStart && date < summerStart) { season = "spring"; } else if (date >= summerStart && date < autumnStart) { season = "summer"; } else if (date >= autumnStart && date < winterStart) { season = "autumn"; } else if (date >= winterStart && date < springStart) { season = "winter"; } else { return "winter"; } return season; }
失败的测试用例
it.optional('throws an error with message "Invalid date!" on tricky moment', function () { const fakeDate = { toString() { return Date.prototype.toString.call(new Date()); }, [Symbol.toStringTag]: 'Date' }; Object.setPrototypeOf(fakeDate, Object.getPrototypeOf(new Date())); const res = checkForThrowingErrors.call(this, [ () => getSeason(fakeDate) ], 'Invalid date!'); assert.strictEqual(res.every($ => $ === CORRECT_RESULT_MSG), true); });
问题分析与解决方法
问题根源
当前的isValidDate函数使用d instanceof Date && !isNaN(d)进行校验:
d instanceof Date会被伪造对象绕过,因为测试用例给对象设置了Date原型;!isNaN(d)仅判断对象转换为数字是否有效,伪造对象可通过重写valueOf方法返回有效数字来绕过,此时函数会继续执行后续代码,调用date.getFullYear()等方法时,由于伪造对象没有Date实例的内部时间值,会抛出非预期错误或返回无效值,导致测试失败。
解决方法
修改isValidDate函数,使用d.getTime()来判断日期有效性——真正的有效Date实例调用getTime()会返回时间戳数字,无效Date实例和伪造对象调用getTime()都会返回NaN:
const isValidDate = (d) => { return d instanceof Date && !isNaN(d.getTime()); };
修改后的函数会正确识别伪造对象,抛出"Invalid date!"错误,满足测试用例要求。
内容的提问来源于stack exchange,提问作者plur
相关产品推荐
相关产品推荐

