纯函数应该如何读取配置文件或打开数据库



我的函数通常需要配置文件或数据库中的数据。我更喜欢尽可能纯的函数和可以进行单元测试的东西。

我不知道如何正确地做到这一点,因为我没有CS学位。我能看到的选项是:

示例1:

function myFunc(p1, p2, db, configFile) { ... }

但这意味着调用CCD_ 1的所有其他函数也需要将CCD_。

示例2:

function myFunc(p1, p2) { 
const config = readConfig();
dbConn = openDb();    
...
}

我想这会让单元测试变得不可能吗?

示例3:

const struct = {
config: readConfig(),
dbConn: openDb(),
...
};
function myFunc(p1, p2, struct) { ... }

这有一个不利的方面,即当其他函数的数据也存储在这个全局struct中时,每个函数都可以访问超出其需要的内容。

问题

还有其他可能性吗?建议的方法是什么?

我认为您可以在这里使用依赖注入。类似这样的东西:

function readConfig() { 
// returns real config
}
function openDb() {
// return real db connection
}
function readConfigMock() { 
// returns mock config
}
function openDbMock() {
// return mock db connection
}
function myFuncBuilder(readConfigFn, openDbFn) { 
return function(p1, p2) {
// can use readConfigFn everywhere because of closure
const config = readConfigFn();
dbConn = openDbFn();    
...
}
}
const myFunc = myFuncBuilder(readConfig, openDb);
// no need to know about openDb and readConfig
function topFunc() {
myFunc(p1, p2);
}
// code
const myFunc = myFuncBuilder(readConfig, openDb);
// test
const myFunc = myFuncBuilder(readConfigMock, openDbMock);

诀窍是将函数作为参数传递。此外,还有一个高阶函数(返回函数的函数(,称为myFuncBuilder。此函数基于两个参数构建myFunc——用于数据库连接的函数和用于配置的函数。

因此,您可以轻松地创建readConfigopenDb的mock进行测试。

另外,函数编程范式教我们在这种情况下使用IO monad。但是在JS/TS中使用monad有一个非常陡峭的学习曲线。

这样定义myFunc()以保持其纯粹性:

function myFunc(p1, p2, readConfig, openDb) { ... }

并将其称为封闭范围

// other code here
{
const config = readConfig();
const dbConn = openDb();
myFunc(p1, p2, readConfig, openDb);
}
// other code here
// config and dbConn isn't available here

A PoC:

function func(a, b) {
console.log(a);
console.log(b);
}
const a = undefined;
const b = undefined;
{
const a = 'private1';
const b = 'private2';
func(a, b);
}
console.log(a);
console.log(b);

相关内容

最新更新