nodejs/mocha/chai as promise : 在外部初始化的预期异步函数中使用的变量

nodejs/mocha/chai as promise : variables used in expected async function initialized outside

我是 mocha/chai 的新手,我花了 2 天时间尝试解决以下问题但没有成功(请注意,下面的代码只是为了展示概念,它不是真实的) .

我有一个名为"api.js"的JS文件,其中SERVER_URL等变量是通过dotenv框架在文件顶部初始化的。

api.js :

const SERVER_URL = process.env.SERVER_URL;

async function startAPI () {
  return new Promise ( (resolve, reject) => {
                                             console.log(`${SERVER_URL}`);
                                             resolve();
                                            });
exports = {startAPI};

现在我得到 "test.js" 文件,其中:

test.js:

require('../api');

it('the test', async () => {
  return await expect(api.startAPI()).to.be.fulfilled;
});

问题是 SERVER_URL 在测试期间未定义,我无法修改 api.js (因为我不是所有者),只能修改 test.js.

我如何 运行 正确设置 SERVER_URL 变量的测试(api.js 的 process.env.SERVER_URL 值)?

有没有不重构的解决方案?

如果不是,最好的解决方案是什么?

专家,在此先感谢您的宝贵帮助

最简单的方法就是在您 运行 从 CLI 进行测试时设置这些变量:

例如在 npm 脚本中:

"scripts": {
  "test": "SERVER_URL='http://example.com' mocha"
}

或直接从终端:

$ SERVER_URL='http://example.com' npm test

但更好的解决方案是在测试中模拟环境变量,几乎不需要重构。并且需要安装 proxyquire。实际上这里不需要async/await

const proxyquire = require('proxyquire').noPreserveCache() // noPreserveCache is important to always have refreshed script with new process.env.SERVER_URL in each test

const MOCKED_SERVER_URL = 'http://example.com'

describe('example', () => {
  let initialServerUrl
  let api

  beforeEach(() => {
    initialServerUrl= process.env
  })

  afterEach(() => {
    process.env = initialServerUrl
  })

  it('fulfilled', () => {
    process.env.USE_OTHER_CODE_PATH = MOCKED_SERVER_URL 
    api = proxyquire('../api', {})
    return expect(api.startAPI()).to.be.fulfilled
  })

  it('rejected', () => {
    process.env.USE_OTHER_CODE_PATH = ''
    api = proxyquire('../api', {})
    return expect(api.startAPI()).to.be.rejected
  })
})

您可以使用以下行使用 mocha 设置 .env 变量:

env SERVER_URL=htt://api.yourserver.com/ mocha test

这样 mocha 就知道您的 process.env.SERVER_URL

会得到什么

一种提高可测试性的方法是在可能的情况下使用 process.env.SERVER_URL 而不是 SERVER_URL - 或者 getServerUrl():

const getServerUrl = () => process.env.SERVER_URL;

这样 process.env.SERVER_URL 可以在任何时候被嘲笑。

另一种方法是在 process.env.SERVER_URL 被模拟后导入模块。如果有不止一个测试使用这个模块,这应该涉及去缓存,否则它不会被重新评估。

const decache = require('decache');

...
let originalServerUrl;

beforeEach(() => {
  originalServerUrl = process.env.SERVER_URL;
});

beforeEach(() => {
  process.env.SERVER_URL = originalServerUrl;
});

it('the test', async () => {
  decache('../api');
  process.env.SERVER_URL = '...';
  const api = require('../api');
  await expect(api.startAPI()).to.be.fulfilled;
});

如果预计在测试中没有SERVER_URL,可以在mock之后直接丢弃: