如何在 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'

【讨论】:

underscoreclone 函数可以代替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?的主要内容,如果未能解决你的问题,请参考以下文章

如何在RSpec中存根?

如何在 JUnit Test Java 中替换 Mockito 以存根类

如何在 .NET Core 中模拟/存根 HttpRequestMessage?

如何在 Flutter 中存根目标平台

如何使用 cy.intercept() 使用不同的存根存根两个请求?

如何在 UITesting 上存根网络请求