如何使用 Jest 在单元测试中模拟 NODE_ENV

How to mock NODE_ENV in unit test using Jest

我想在其中一个单元测试中设置 NODE_ENV,但它总是设置为测试,所以我的测试失败了。

loggingService.ts

...

const getTransport = () => {
  if (process.env.NODE_ENV !== "production") {
    let console = new transports.Console({
      format: format.combine(format.timestamp(), format.simple()),
    });
    return console;
  }

  const file = new transports.File({
    filename: "logFile.log",
    format: format.combine(format.timestamp(), format.json()),
  });
  return file;
};

logger.add(getTransport());
const log = (level: string, message: string) => {
  logger.log(level, message);
};

export default log;

loggingService.spec.ts

     ...
    describe("production", () => {
        beforeEach(() => {
          process.env = {
            ...originalEnv,
            NODE_ENV: "production",
          };
    
          console.log("test", process.env.NODE_ENV);
          log(loglevel.INFO, "This is a test");
        });
    
        afterEach(() => {
          process.env = originalEnv;
        });
    
        it("should call log method", () => {
          expect(winston.createLogger().log).toHaveBeenCalled();
        });
    
        it("should not log to the console in production", () => {
          expect(winston.transports.Console).not.toBeCalled();
        });
    
        it("should add file transport in production", () => {
          expect(winston.transports.File).toBeCalledTimes(1);
        });
      });
...

如何在我的测试中将 process.env.NODE_ENV 设置为生产环境,最好是在 beforeEach 中,这样我的服务中的 if 块为 false 并返回文件传输。为了简洁起见,我省略了一些代码。

您面临的核心问题是,一旦您尝试将要测试的文件导入到您的测试套件中,其中的代码将立即被评估,隐式调用的函数将被已执行,这意味着 logger.add(getTransport()); 将在 beforeEach 等任何函数有机会设置环境变量之前被调用。

解决此问题的唯一方法是使用以下方法:

您首先需要将 process.env.NODE_ENV 环境变量分配给另一个文件中的常量变量。暂且称它为environmentVariables.ts,其内容如下:

export const ENVIRONMENT = process.env.NODE_ENV;

然后我们将不得不重构 getTransport 以使用此变量,如下所示:

const getTransport = () => {
  if (ENVIRONMENT !== "production") {

在您的测试套件中,您将不得不模拟 const 文件,这将允许您更改 ENVIRONMENT 变量的设置。注意 ../src/environmentVariables 是一个示例目录,您必须实际定义此文件的相关目录是什么。另外确保这在 describe 子句之外,最好在上面以提高可读性:

jest.mock('../src/environmentVariables', () => ({
  ENVIRONMENT: 'production',
}));

然后您的单元测试将以 ENVIRONMENT 执行 production