簡體   English   中英

如何模擬作為被測服務依賴項的常量?

[英]How to mock a constant that is a dependency of the service under test?

我正在測試一個名為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模擬 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
}

這是正確的方法嗎? 完成此任務的最佳方法是什么?

Mocking 內部依賴

mocking internal dependency之前,這個問題需要弄清楚它的意義何在; 因為 Jest 的 mocking 能力有些受限。 由於問題中沒有提到,我個人選擇了一些最好的例子。

為了更容易理解,假設有一個虛構的 function 叫做testFunction() 它是一個 function,返回前面提到的storageConnectionString

1. 僅針對測試 scope 中的特定 function,僅此而已。

// 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 只能更換一個 function 或 module 它不能重新評估代碼。 在這種情況下, 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 的內部模塊 mocking 軟解耦。

工作代碼為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. mocking 單個變量

正如案例 2 中已經解釋的那樣,這是不可能的情況。 Jest 不能模擬單個變量 它可能最接近問題中提到的代碼,這就是需要澄清的原因。

// 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 中提到的硬解耦方法用於一般用途,但在很多情況下它並不完全適合。 選擇最適合您的情況。

暫無
暫無

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

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