如何在 node.js 中存根 process.env?
Posted
技术标签:
【中文标题】如何在 node.js 中存根 process.env?【英文标题】:How to stub process.env in node.js? 【发布时间】:2014-08-26 15:53:35 【问题描述】:我想用bar
存根process.env.FOO
。
var sinon = require('sinon');
var stub = sinon.stub(process.env, 'FOO', 'bar');
我很困惑。 看了文档,还是没看懂。sinonjs docs
sinonjs就是一个例子,不是sinonjs也可以。
【问题讨论】:
您能解释一下为什么要存根环境变量吗?您是在类 unix 的操作系统或 Windows 上执行此操作吗? @slebetman 通常依赖环境变量进行配置,例如您所依赖的服务的 API 密钥。见12factor.net。 @AndrewHomeyer:是的,但你不存根它们——你为测试正确设置了它们 【参考方案1】:根据我对process.env
的理解,在设置其属性时,您可以像对待任何其他变量一样简单地对待它。但请记住,process.env
中的每个值都必须是字符串。因此,如果您在测试中需要特定值:
it('does something interesting', () =>
process.env.NODE_ENV = 'test';
// ...
);
为避免将状态泄漏到其他测试中,请务必将变量重置为其原始值或完全删除它:
afterEach(() =>
delete process.env.NODE_ENV;
);
【讨论】:
它对我有用。要记住的一件事是,如果您正在测试一个在模块首次加载时读取 NODE_ENV 的模块,您可能希望在加载模块之前设置 NODE_ENV(即 NODE_ENV 可以在 beforeEach 中设置)块。)这可能看起来很明显,但它之前已经绊倒了我。 如果您遇到问题,您可以发布一个代码 sn-p 供某人查看吗?我在写答案时考虑了 Mocha 测试运行程序的语法,但它也应该适用于任何其他运行程序(例如实验室)。 这行得通,但我在使用jest
时发现了一个怪癖。在我的生产代码中,我从 env 分配给一个 const(例如const X = process.env.X
)。 const 是在(ES)模块范围内声明的,而不是在函数范围内。我的测试在重试运行时总是以jest --watch
通过,但在第一次运行时总是失败。这里有一个我不完全理解的订购问题。只需确保您始终在生产代码中(即在函数中)直接从 process.env
读取,而不是在模块级别缓存它。
如果您正在评估函数中的 process.env,这很有效,但如果它是常量,则不会。例如,如果您在测试中设置 process.env.value,我有 const myValue = process.env.value ? process.env.value : 'default'
将不起作用。但是,const myValue = () => (process.env.value ? process.env.value : 'default'
) 按预期工作!
以同样的方式,我有:const SWITCH_ON = (process.env.SWITCH_ON.toLowerCase() === 'true');
这不起作用所以我将其更改为两行:var switchOn = process.env.SWITCH_ON; const SWITCH_ON = (switchOn === undefined ? false : switchOn.toLowerCase() === 'true');
最初一直给我undefined
错误,我正在做@ 987654334@【参考方案2】:
我能够通过克隆process.env
在我的单元测试中正确地存根它并使用拆卸方法恢复它。
使用 Mocha 的示例
const env = Object.assign(, process.env);
after(() =>
process.env = env;
);
...
it('my test', ()=>
process.env.NODE_ENV = 'blah'
)
请记住,这仅在您正在测试的函数中读取 process.env 时才有效。例如,如果您正在测试的代码读取变量并在闭包中使用它,它将无法工作。您可能使缓存的要求无效以正确测试。
例如以下不会有 env 存根:
const nodeEnv = process.env.NODE_ENV;
const fnToTest = () =>
nodeEnv ...
【讨论】:
这个过程大部分都有效。我不得不调整“之后”的方法。after(() => process.env = Object.assign(, env); );
否则测试将操纵共享副本。需要在每次测试后设置一个新版本。
@Kyle.. 不会吧?假设您在文件顶部设置了一次 env,它将恢复到测试套件开始时的状态..【参考方案3】:
使用 sinon,您可以像这样对任何变量进行存根。
const myObj =
example: 'oldValue',
;
sinon.stub(myObj, 'example').value('newValue');
myObj.example; // 'newValue'
这个例子是表单 sinon 文档。 https://sinonjs.org/releases/v6.1.5/stubs/
有了这些知识,您就可以存根任何环境变量。 在您的情况下,它看起来像这样:
let stub = sinon.stub(process.env, 'FOO').value('bar');
【讨论】:
我收到一个错误“无法存根不存在的自有属性 FOO”。虽然也使用 wallaby.js 来运行我的测试。 感谢您发布“存根 env var 是什么样的?”问题的答案。而不是仅仅说我们不需要,因为我们可以手动操作它们:) 我遇到了与@WillLovett 相同的错误,并通过在我的单元测试脚本顶部附近添加 require 调用来解决它:require('dotenv').config();
我意识到这通常会在我的应用程序运行时被调用,但是如果我直接运行我的单元测试,这个 require 语句将会丢失。【参考方案4】:
如何在单元测试期间快速模拟 process.env。
https://glebbahmutov.com/blog/mocking-process-env/
const sinon = require('sinon')
let sandbox = sinon.createSandbox()
beforeEach(() =>
sandbox.stub(process.env, 'USER').value('test-user')
)
it('has expected user', () =>
assert(process.env.USER === 'test-user', 'wrong user')
)
afterEach(() =>
sandbox.restore()
)
但是在测试之前 process.env 中可能不存在的属性呢?您可以使用以下包,然后您将能够测试不存在的环境变量。
https://github.com/bahmutov/mocked-env
【讨论】:
当process.env.USER
还没有值时,这将不起作用。【参考方案5】:
在spec-helper.coffee
或类似设置您的 sinon 沙箱的地方,跟踪原始的 process.env
并在每次测试后恢复它,这样您就不会在测试之间泄漏,也不必记住每次都重置。
_ = require 'lodash'
sinon = require 'sinon'
beforeEach ->
@originalProcessEnv = _.cloneDeep process.env
afterEach ->
process.env = _.cloneDeep @originalProcessEnv
在您的测试中,照常使用process.env
。
it 'does something based on an env var', ->
process.env.FOO = 'bar'
【讨论】:
underscore
的clone
函数可以代替cloneDeep
- 如果您已经在使用underscore
而不是lodash
,这很有用。【参考方案6】:
如果你想存根一个不在 process.env 中的键,你可以使用它
const sinon = require('sinon')
let sandbox = sinon.createSandbox();
sandbox.stub(process, 'env').value( 'SOME_KEY': 'SOME_VALUE' );
【讨论】:
【参考方案7】:就像许多其他人指出的那样,除非您在测试开始之前设置了环境变量,否则 sinon 方式有效,例如在您正在测试的文件中,如下所示:
const foo = process.env.YOUR_VAR;
Gleb Bahmutov 编写了一个 npm 包,它提供了一种在测试中设置环境变量的好方法,无论您如何引用环境变量。
链接到他的页面:https://glebbahmutov.com/blog/mocking-process-env/
npm 包链接:https://github.com/bahmutov/mocked-env
效果很好,而且非常容易实现。
【讨论】:
以上是关于如何在 node.js 中存根 process.env?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JUnit Test Java 中替换 Mockito 以存根类
如何在 .NET Core 中模拟/存根 HttpRequestMessage?