javascript 如何模拟一个依赖于被测服务的常量?

unhi4e5o  于 2022-12-02  发布在  Java
关注(0)|答案(1)|浏览(119)

bounty将在3天后过期。回答此问题可获得+50声望奖励。mcool希望吸引更多人关注此问题。

我正在测试一个名为connect-key.js的文件。它有一个名为keyvault-emulator的依赖项。
档案#1:

// connect-key.js file
const { save, retrieve, init  } = require('./keyvault-emulator')
....
....
....
// SOME TESTS

文件2:

// The keyvault-emulator.js file
const { storageConnectionString } = require('../config')

现在,我如何从我的测试文件connect-key.spec.js中模拟storageConnectionString的值?
我设想的是这样的:

// The connect-key.spec.js file
const keyvault_emulator = require('../keyvault-emulator');
const spy = jest.spyOn(keyvault_emulator, 'storageConnectionString');
spy.mockReturnValue('');

下面是配置文件:

// config.js file
module.exports = {
  storageConnectionString: process.env.STORAGE_CONNECTION_STRING || process.env.Storage,
  keyVaultName: process.env.KEY_VAULT
}

这是正确的方法吗?实现这一点的最佳方法是什么?

jmo0nnb3

jmo0nnb31#

模拟内部依赖关系

在嘲弄内部依赖性之前,这个问题需要澄清它的意义何在;因为杰斯特的嘲讽能力有些有限,问题中没有提到,所以我亲自挑选了一些最好的例子。
为了更容易理解,假设有一个虚函数testFunction();它是返回前面提到的storageConnectionString的函数。

1.仅针对测试范围内的特定功能,不针对其他功能。

// key.spec.js
const keyvault_emulator = require('../keyvault-emulator');
js.mock('../keyvault-emulator', () => ({
  // everything is original, except testFunction
  ...jest.requireActual('../keyvault-emulator'),
  // this supposed to return () => storageConnectionString but it's mocked here.
  testFunction: jest.fn(() => 'mocked')
})

// ✅ it works
expect(keyvault_emulator.testFunction()).toEqual('mocked')
// ❌ this fails!
expect(keyvault_emulator.otherFunctionUsingStorageConnectionString())
  .toEqual('mocked')

2.用于模块内的所有内容

Jest只能替换一个函数或模块。它不能重新计算代码。在这种情况下,config.jskeyvault-emulator.js的依赖关系必须从源代码中分离出来,以简化测试过程。

2 - 1.与源本身的硬去耦。

// keyvault-emulator.js
// KeyValue emulator has to be restructured to have constructor, or init function
class KeyValueEmulator {
  constructor(config) {
    this.config = config;
  }
  testFunction() {
    // do something with this.config
    return this.config;
  }
}

// key.spec.js
const mockedConfig = { storageConnectionConfig: 'mocked' }
const keyValueEmulator = new KeyValueEmulator(mockedConfig);
// ✅ it works
expect(keyValueEmulator.testFunction()).toEqual('mocked')

2 - 2.使用jest的内部模块模拟实现软解耦。

Github处的工作代码

// key.spec.js
import config from "./config";
jest.mock("./config", () => ({ default: { storageConnectionString: "mocked" } }));
import { storageConnectionString, testFunction } from "./index";

describe("config mocking", () => {
  it("value is mocked", () => {
    // ✅ it works
    expect(config.storageConnectionString).toEqual("mocked");
    expect(testFunction()).toEqual("mocked");
  });
});

3.模拟单个变量

正如已经在案例2中解释的,这是不可能的案例。玩笑不能模拟单个变量;它可能与问题中提到的代码最接近,因此需要加以澄清。

// same as code in the question. the test code should be fixed to work,
// but let's say it's working as you've intended.
// key.spec.js
const keyvault_emulator = require('../keyvault-emulator');
const spy = jest.spyOn(keyvault_emulator, 'storageConnectionString');
spy.mockReturnValue('mocked');
// ✅ it may work...but
expect(keyvault_emulator.storageConnectionString).toEqual('mocked')
// ❌ this fails!
expect(keyvault_emulator.testFunction()).toEqual('mocked')

那么,最好的办法是什么?
这是正确的方法吗?实现这一点的最佳方法是什么?
就像开发者世界中的许多情况一样,这取决于具体情况。就我个人而言,我会选择2 - 1中提到的一种硬解耦方法用于一般用途,但在许多情况下,它并不完全适合。选择最适合您的情况的方法。

相关问题