如何使用 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
。
我想在其中一个单元测试中设置 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
。