VoY*_*VoY 7 javascript unit-testing functional-programming pure-function
在我们的JavaScript开发团队中,我们采用了redux/react风格编写纯函数代码.但是,我们似乎无法对我们的代码进行单元测试.请考虑以下示例:
function foo(data) {
return process({
value: extractBar(data.prop1),
otherValue: extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
此函数调用取决于对其的调用process,extractBar并且extractBaz每个调用都可以调用其他函数.总之,他们可能需要data构造一个非平凡的模拟 参数来进行测试.
我们是否应该接受制作这样一个模拟对象的必要性,并且实际上在测试中这样做,我们很快发现我们有难以阅读和维护的测试用例.此外,它很可能会导致遍地测试同样的事情,作为单元测试process,extractBar并且extractBaz可能应该也可以写.通过foo接口测试由这些函数实现的每个可能的边缘情况是不实用的.
我们有一些解决方案,但并不真正喜欢任何解决方案,因为它们似乎都不是我们之前看到过的模式.
解决方案1:
function foo(data, deps = defaultDeps) {
return deps.process({
value: deps.extractBar(data.prop1),
otherValue: deps.extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
解决方案2:
function foo(
data,
processImpl = process,
extractBarImpl = extractBar,
extractBazImpl = extractBaz
) {
return process({
value: extractBar(data.prop1),
otherValue: extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
foo当依赖函数调用的数量增加时,解决方案2 非常快速地污染方法签名.
解决方案3:
只需接受这foo是一个复杂的复合操作并将其作为一个整体进行测试的事实.所有缺点都适用.
请提出其他可能性.我想这是一个功能编程社区必须以某种方式解决的问题.
您可能不需要任何您考虑过的解决方案.函数式编程和命令式编程之间的区别之一是函数式应该生成更容易推理的代码.不仅仅是在精神上"玩编译器"并模拟给定输入集合会发生什么,而是在更多数学意义上推理你的代码.
例如,单元测试的目标是测试"可以破坏的所有东西".看看你发布的第一个代码片段,我们可以推断出这个功能,然后问:"这个功能怎么会破坏?" 这是一个足够简单的功能,我们根本不需要编译器.我们可以说,如果process()函数未能为给定的一组输入返回正确的值,即如果它返回了无效结果或者它是否引发了异常,那么函数就会中断.这反过来意味着我们还需要测试是否extractBar()并extractBaz()返回正确的结果,以便传递正确的值process().
实际上,你只需要测试是否foo()会抛出意外的异常,因为它只是调用process(),你应该process()在它自己的单元测试集中进行测试.同样的事情extractBar()和extractBaz().如果这两个函数在给定有效输入时返回正确的结果,它们将传递正确的值process(),如果process()在给定有效输入时产生正确的结果,那么foo()也将返回正确的结果.
你可能会说,"参数怎么样?如果它从data结构中提取错误值会怎样?" 但真的可以打破吗?如果我们查看函数,它使用核心JS点表示法来访问对象的属性.我们不会在我们的应用程序的单元测试中测试语言本身的核心功能.我们可以查看代码,原因是它基于硬编码的对象属性访问提取值,并继续我们的其他测试.
这并不是说你可以抛弃你的单元测试,但是许多经验丰富的函数程序员发现他们需要的测试要少得多,因为你只需要测试可以破坏的东西,而函数式编程会减少测试数量.可破坏的东西,所以你可以把你的测试集中在真正有风险的部分.
顺便说一句,如果你正在处理复杂的数据,并且你担心即使使用FP也可能很难推断所有可能的排列,你可能想要研究生成测试.我认为那里有一些JS库.
| 归档时间: |
|
| 查看次数: |
326 次 |
| 最近记录: |