簡體   English   中英

在 Jest for Node 應用程序中模擬環境和/或導出常量

[英]Mocking environment and/or exported constants in Jest for Node apps

設置

我在一個 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_SOURCEID_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();
    }
});

由於上述評論中所述的原因,模擬環境也不起作用......模塊在導入時進行評估,並且在模擬更改它們之前從環境中初始化這些變量。

行為

ID_SOURCEID_PROVIDER始終具有從環境分配給它們的值。

當然,一個明顯的解決方案是從函數定義中的常量中訪問變量,這些變量只會在調用時執行……但問題是,在我使用這種模式的代碼庫中,我使用的是EVERYWHERE 我不能隨便開始任意重構一切來讓這個工作,我覺得必須有更好的方法。

我嘗試過的其他事情

我也嘗試過mocked-env ,但由於與上述相同的原因而失敗。 我試過在beforeEach鈎子中調用jest.resetModules並在每個測試中的模塊中調用,但這種模式到目前為止還沒有產生任何結果。 如果是這樣的話,我有興趣了解更多關於這種模式的信息。

我認為使用 jest setupFiles 的方法可能是解決方案,因為我在其他情況下使用它們,在這些情況下,環境變量需要在本地(隨處)可用,但不存在,但我不希望每次測試都在全局范圍內模擬這些...只有一項測試。

這樣做的正確模式是什么?

在我的 Jest 配置中,我添加了一個包含我為測試定義的環境的文件。

setupFiles: [
    '<rootDir>/src/.env.testing.js',
],

在這個文件中,我然后設置我使用的環境:

process.env.PORT='9999';

然后我讓我的正常服務根據需要從環境中讀取配置。 你可以為 setupFiles 使用任何文件名,我正在復制我對 .env 文件的使用。

最終,這就是我為修復它所做的。

    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: "foo@bar.com" }});
        const res = makeRes();

        const { updateUserProfile } = await import(
            "../src/controller"
        );

        await updateUserProfile(req, res);

        expect(res.status).toHaveBeenCalledWith(500);
    })

最大的問題之一是確保在模擬常量文件之前清除 require 緩存。 然后,這只是我模擬了常量模塊之后動態導入被測模塊的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM