設定
我在一個 express 應用程式中有一個模塊,我試圖測驗它使用從模塊匯出的常量。許多這些常量來自環境變數。
// src/constants.js
export default {
ID_SOURCE: process.env.ID_SOURCE,
ID_PROVIDER: process.env.ID_PROVIDER
};
/*
process.env {
ID_SOURCE: 'foo',
ID_PROVIDER: 'bar'
}
*/
這是在被測模塊中獲取這些常量的模式。
import constants from './constants';
import { errors } from './errors';
const { ID_SOURCE, ID_PROVIDER } = constants;
export const moduleUnderTest = async (req, res) => {
if (!ID_SOURCE || !ID_PROVIDER) {
if (!ID_SOURCE) logService('ID_SOURCE not provided');
if (!ID_PROVIDER) logService('ID_PROVIDER not provided');
throw { err: errors.unexpectedError };
};
// ... do stuff
return res.status(200).json({ cool: 'beans' });
}
我想測驗不存在環境變數的例外場景。這在模塊中的當前模式下被證明是困難的,因為即使我模擬環境,模塊也會被評估——并且模塊中的ID_SOURCE和ID_PROVIDER常量在環境改變之前被初始化。
重要的是,我只想更改ONE TEST的常量。這是我嘗試過的。
考試
import constants from './constants';
import { moduleUnderTest } from './moduleUnderTest';
describe('Test module', () => {
beforeEach(() => {
jest.clearAllMocks();
})
test('test exception scenario', async () => {
jest.doMock('./constants', () => {
const actualConstants = jest.requireActual('./constants');
return {
__esModule: true,
...actualConstants,
ID_SOURCE: undefined,
ID_PROVIDER: undefined
}
});
// ... assume req/res are available
try {
await moduleUndertest(req, res);
} catch(ex) {
// by the time we get here, the variables are set from the environment still
// because the module was evaluated and ID_SOURCE and ID_PROVIDER variables in the closure set
// before mocking the constants
expect(ex.message).toBeDefined();
}
});
Mocking the environment will not work either for the reason stated in the comments above... the module is evaluated at import and those variables are initialized from the environment before the mock changes them.
Behavior
ID_SOURCE and ID_PROVIDER always have the values assigned to them from the environment.
Of course one obvious solution is just to access the variables out of the constants in the function definition, which will only execute at their invocation... but the problem is that in the codebase I am working in this pattern is EVERYWHERE. I can't just start arbitrarily refactoring everything to make this work, and I feel that there has to be a better way.
Other things I've tried
我也試過mocked-env,由于與上述相同的原因而失敗。我試過在每個測驗中呼叫jest.resetModules一個beforeEach鉤子并在模塊中要求,但這種模式到目前為止還沒有產生任何結果。如果是這樣的話,我有興趣了解更多關于這種模式的資訊。
我認為使用 jest setupFiles 的方法可能是解決方案,因為我在其他情況下使用它們,在這些情況下,環境變數需要在本地(隨處)可用,但不存在,但我不希望每次測驗都在全域范圍內模擬這些...只有一項測驗。
這樣做的正確模式是什么?
uj5u.com熱心網友回復:
在我的 Jest 配置中,我添加了一個包含我為測驗定義的環境的檔案。
setupFiles: [
'<rootDir>/src/.env.testing.js',
],
在這個檔案中,我然后設定我使用的環境:
process.env.PORT='9999';
然后我讓我的正常服務根據需要從環境中讀取配置。你可以為 setupFiles 使用任何檔案名,我正在復制我對 .env 檔案的使用。
uj5u.com熱心網友回復:
最終,這就是我為修復它所做的。
test('should process exception', async () => {
jest.resetModules(); // clear require.cache
jest.doMock('../src/constants', () => {
const constants = jest.requireActual('../src/constants');
console.log(constants);
return {
__esModule: true,
default: {
...constants,
ID_SOURCE: 'foo'
}
}
});
const req = makeReq({ session: { email: "[email protected]" }});
const res = makeRes();
const { updateUserProfile } = await import(
"../src/controller"
);
await updateUserProfile(req, res);
expect(res.status).toHaveBeenCalledWith(500);
})
最大的問題之一是確保在模擬常量檔案之前清除 require 快取。然后,這只是在我模擬了常量模塊之后動態匯入被測模塊的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/328755.html
標籤:javascript 节点.js 单元测试 玩笑 嘲笑
