Я тестирую файл с именем 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')
Теперь, как я могу смоделировать значение storageConnectionString
из моего тестового файла connect-key.spec.js
?
Я представляю что-то вроде этого:
// 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
}
Это правильный способ сделать это? Каков наилучший способ добиться этого?
Прежде чем издеваться над внутренней зависимостью, вопрос должен прояснить, в чем ее смысл; потому что насмешливые способности Джеста несколько ограничены. Поскольку это не было упомянуто в вопросе, я лично выбрал несколько наилучших возможных случаев с примерами.
Чтобы было легче понять, предположим, что есть воображаемая функция с именем testFunction()
; это функция, которая возвращает упомянутое ранее storageConnectionString
.
// 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')
Jest может заменить только функцию или модуль. Он не может переоценивать коды. В этом случае зависимость config.js
и keyvault-emulator.js
должна быть отделена от источника, чтобы упростить процесс тестирования.
// 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')
рабочие коды на 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");
});
});
Как уже объяснялось в случае 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, для общего использования, но во многих случаях он не подходит идеально. Выберите тот, который лучше всего подходит для вашего случая.