单元测试中传递getDayFn函数比currentDay值更优的原因是什么?
我在阅读一本单元测试书籍时看到如下代码片段:
const SUNDAY = 0; ... const SATURDAY = 6; const verifyVoucher1 = (currentDay) => { if ([SATURDAY, SUNDAY].includes(currentDay)) { return false; } return true; }; const verifyVoucher2 = (getDayFn) => { const dayOfWeek = getDayFn(); if ([SATURDAY, SUNDAY].includes(dayOfWeek)) { return false; } return true; };
作者称verifyVoucher2优于verifyVoucher1,原因是verifyVoucher1要求所有调用者都需掌握日期处理方式,过于“繁琐”。但我对此存疑:verifyVoucher2的调用者仍需自行编写函数并传入,仅将日期包装在函数中,那么传递getDayFn而非currentDay到底有什么技术优势?
核心技术优势解析
单元测试可控性大幅提升:这是最关键的一点。测试
verifyVoucher1时,你得手动传入0-6的数字模拟不同星期,但测试verifyVoucher2时,直接传一个返回固定值的模拟函数就行——比如() => 0模拟周日,() => 1模拟周一,完全不受真实系统时间影响,测试用例稳定且能精准覆盖所有分支,编写效率高得多。职责分离,减少重复错误:
verifyVoucher的核心职责是判断优惠券是否可用,不该掺和“获取当前星期几”的逻辑。verifyVoucher1把日期获取的责任甩给每个调用方,一旦有调用方写错(比如把getDay()写成getDate()),直接就会出bug。而verifyVoucher2只负责验证逻辑,调用方可以统一封装一个靠谱的日期获取函数到处复用,避免重复造轮子和低级错误。灵活性与扩展性更强:如果后续业务需求变化,比如要支持时区切换、或者测试特定日期的场景,
verifyVoucher2只需要更换传入的getDayFn即可,验证函数本身完全不用修改。比如要测试纽约时区的周日,就传一个返回纽约时区星期几的函数;但verifyVoucher1得让每个调用方先处理好时区再传值,改动成本高很多。消除隐式依赖,降低沟通成本:
verifyVoucher1要求调用方必须知道要传“当前星期几的数字”,这是个隐式约定,新人接手很容易搞错。而verifyVoucher2通过传入函数,把“获取当前日期”这个动作明确化——调用方只需要传一个能拿到正确星期几的函数就行,不用关心验证逻辑里怎么使用这个值,减少了理解和沟通成本。
内容的提问来源于stack exchange,提问作者user22155685

