用Jest测试process.env


114

我有一个取决于环境变量的应用程序,例如:

const APP_PORT = process.env.APP_PORT || 8080;

我想测试例如:

  • 可以通过节点env变量设置APP_PORT。
  • 或某个express应用程序正在使用以下命令设置的端口上运行process.env.APP_PORT

我如何用Jest做到这一点?我可以process.env在每次测试之前设置这些变量,还是应该以某种方式模拟它?


是的,您可以设置环境变量
Deep Kakkar

@Deep AFAIK我只能在玩笑配置中设置一次。
Tomasz Mularczyk

Answers:


154

我这样做的方式可以在这个SO问题中找到

在每次测试之前重置模块,然后在测试内部动态导入模块,这一点很重要:

describe('environmental variables', () => {
  const OLD_ENV = process.env;

  beforeEach(() => {
    jest.resetModules() // most important - it clears the cache
    process.env = { ...OLD_ENV }; // make a copy
  });

  afterAll(() => {
    process.env = OLD_ENV; // restore old env
  });

  test('will receive process.env variables', () => {
    // set the variables
    process.env.NODE_ENV = 'dev';
    process.env.PROXY_PREFIX = '/new-prefix/';
    process.env.API_URL = 'https://new-api.com/';
    process.env.APP_PORT = '7080';
    process.env.USE_PROXY = 'false';

    const testedModule = require('../../config/env').default

    // ... actual testing
  });
});

如果您在运行Jest之前寻找一种加载env值的方法,请寻找以下答案。您应该为此使用setupFiles


2
请提供完整的答复
Yves M.

对我来说很棒。如果需要使用默认导出,则可以执行以下操作:const testingModule = require('../../ config / env')。default;
阿齐兹

6
如果这对您不起作用,请确保当您在实际代码中读取env变量时,是在函数/受限范围内读取它,而不是使全局变量指向process.env.YOUR_VARIABLE。
penguinsource

1
@learner(如果我没记错的话delete process.env.NODE_ENV; )只是我代码中的遗留物,对您而言无关紧要。重要的是您需要jest.resetModules()在测试之前致电,然后在其还原初始process.env对象(OLD_ENV)
Tomasz Mularczyk

1
@MEMark,您需要创建一个副本,以免突变原始对象(以后需要还原)
Tomasz Mularczyk

60

笑话setupFiles是处理此问题的正确方法,您无需安装dotenv,也无需使用任何.env文件即可使其工作。

jest.config.js

module.exports = {
  setupFiles: ["<rootDir>/.jest/setEnvVars.js"]
};

.jest/setEnvVars.js

process.env.MY_CUSTOM_TEST_ENV_VAR = 'foo'

而已。


1
这是开玩笑地处理环境变量的最直接方法,谢谢!
klaevv

24

./package.json

"jest": {
  "setupFiles": [
    "<rootDir>/jest/setEnvVars.js"
  ]
}

./jest/setEnvVars.js

process.env.SOME_VAR = 'value';


2
可能是我见过的最简单的方法。无需安装dotenv软件包。
MattC

23

您可以使用setupFiles笑话配置功能。正如文档所说

运行一些代码以配置或设置测试环境的模块的路径列表。每个setupFile将对每个测试文件运行一次。由于每个测试都在其自己的环境中运行,因此这些脚本将在执行测试代码本身之前立即在测试环境中执行。

  1. npm install dotenv 用于访问env变量的dotenv。
  2. .env文件创建到应用程序的根目录,并将此行添加到其中。
#.env
APP_PORT=8080
  1. 创建您的自定义模块文件,其名称为someModuleForTest.js并将此行添加到其中。
//someModuleForTest.js
require("dotenv").config()
  1. jest.config.js像这样更新文件
module.exports = {
  setupFiles: ["./someModuleForTest"]
}
  1. 您可以在所有测试块中访问env的变量。
test("Some test name", () => {
  expect(process.env.APP_PORT).toBe("8080")
})

10

另一个选择是将其添加到定义jest.config.js之后的文件中module.exports

process.env = Object.assign(process.env, {
  VAR_NAME: 'varValue',
  VAR_NAME_2: 'varValue2'
});

这样,就不必ENV在每个.spec文件中定义变量,并且可以全局调整它们。


这是一个了不起的答案。谢谢。
spierce7

3

根据组织代码的方式,另一种选择是将env变量放入运行时执行的函数中。

在此文件中,env var是在导入时设置的,并且需要dynamicrequire才能测试不同的env var(如本答案所述):

const env = process.env.MY_ENV_VAR;

const envMessage = () => `MY_ENV_VAR is set to ${env}!`;

export default myModule;

在此文件中,env var是在envMessage执行时设置的,您应该能够直接在测试中对process.env进行突变:

const envMessage = () => {
  const env = process.env.MY_VAR;
  return `MY_ENV_VAR is set to ${env}!`;
}

export default myModule;

开玩笑的测试:

const vals = [
  'ONE',
  'TWO',
  'THREE',
];

vals.forEach((val) => {
  it(`Returns the correct string for each ${val} value`, () => {
    process.env.MY_VAR = val;

    expect(envMessage()).toEqual(...


0

我认为您也可以尝试以下方法:

const currentEnv = process.env;
process.env = { ENV_NODE: 'whatever' };

// test code...

process.env = currentEnv;

这对我有用,您不需要模块的东西


问题是,如果导入另一个使用process.env的文件,则直接对其进行更改不会产生任何效果。因此,在每次测试之前,您都需要告诉Jest这样的消息-“嘿,再次导入并执行此文件”。
Tomasz Mularczyk,

0

我认为,如果将对环境变量的提取提取到util中,则它会更清晰,更容易理解(如果您始终未设置环境变量,则可能希望包括检查以快速失败),那么您可以模拟该util 。

// util.js
exports.getEnv = (key) => {
    const value = process.env[key];
    if (value === undefined) {
      throw new Error(`Missing required environment variable ${key}`);
    }
    return value;
};

// app.test.js
const util = require('./util');
jest.mock('./util');

util.getEnv.mockImplementation(key => `fake-${key}`);

test('test', () => {...});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.