Як заглушити process.env у node.js?


81

Я хочу недопалок process.env.FOOз bar.

var sinon = require('sinon');
var stub = sinon.stub(process.env, 'FOO', 'bar');

Я збентежений. Я прочитав документ, але все ще не розумію. sinonjs docs

sinonjs - один із прикладів, не sinonjs - це нормально.


Чи можете ви пояснити, чому ви хочете заглушити середовище? Ви робите це в Unix-подібній ОС чи Windows?
slebetman

1
@slebetman прийнято покладатися на змінні середовища для конфігурації, як ключ API для служби, на яку ви покладаєтесь. Дивіться 12factor.net .
Andrew Homeyer

1
@AndrewHomeyer: Так, але ти не заглушиш їх - ти правильно встановив їх для тесту
slebetman

Відповіді:


74

З мого розуміння process.env, ви можете просто ставитись до неї як до будь-якої іншої змінної при встановленні її властивостей. Однак майте на увазі, що кожне значення в process.envмає бути рядком. Отже, якщо вам потрібне певне значення у вашому тесті:

   it('does something interesting', () => {
      process.env.NODE_ENV = 'test';
      // ...
   });

Щоб уникнути перетікання стану в інші тести, переконайтеся, що скинули змінну до початкового значення або взагалі видалили:

   afterEach(() => {
       delete process.env.NODE_ENV;
   });

8
Це працює для мене. Майте на увазі одне: якщо ви тестуєте модуль, який читає NODE_ENV при першій завантаженні модуля, ви, мабуть, захочете встановити NODE_ENV перед завантаженням модуля (тобто NODE_ENV можна встановити в блоці beforeEach.) Це може здатися очевидним , але це мене спотикало раніше.
Терренс,

Якщо у вас виникають проблеми, чи можете ви опублікувати фрагмент коду, щоб хтось подивився? Я написав свою відповідь, маючи на увазі синтаксис пробного бігуна Мокки, але він також повинен працювати з будь-яким іншим бігуном (наприклад, лабораторією).
Джошуа Даттон,

2
Це працює, але при використанні я виявив химерність jest. У своєму виробничому коді я призначив env для const (наприклад const X = process.env.X). Const оголошено в області дії модуля (ES), а не в області функцій. Мої тести завжди проходили з jest --watchповторними тестовими запусками, але завжди проваливались під час першого запуску. Є проблема замовлення, яку я тут не повністю розумію. Просто переконайтеся, що ви завжди читаєте безпосередньо process.envу своєму виробничому коді (тобто у функції), і не кешуєте його на рівні модуля.
Джессі Бьюкенен

1
це добре працює, якщо ви оцінюєте process.env у функції, але не якщо це константа. наприклад, я const myValue = process.env.value ? process.env.value : 'default'б не працював, якщо ви встановите process.env.value всередині тесту. Однак, const myValue = () => (process.env.value ? process.env.value : 'default') працює як слід!
Рафаель Маркес,

У цьому ж ключі у мене було: const SWITCH_ON = (process.env.SWITCH_ON.toLowerCase() === 'true');що не спрацювало, тому я змінив його на два рядки: var switchOn = process.env.SWITCH_ON; const SWITCH_ON = (switchOn === undefined ? false : switchOn.toLowerCase() === 'true');початковий постійно undefined.toLowerCase()
Ентузіаст Скали

25

У process.envмоїх модульних тестах я зміг отримати належний удар, клонуючи його та відновлюючи його методом розірвання.

Приклад використання мокко

const env = Object.assign({}, process.env);

after(() => {
    process.env = env;
});

...

it('my test', ()=> {
    process.env.NODE_ENV = 'blah'
})

Майте на увазі, це буде працювати лише в тому випадку, якщо process.env читається лише у тій функції, яку ви тестуєте. Наприклад, якщо код, який ви тестуєте, читає змінну і використовує її в закритті, це не буде працювати. Ви, мабуть, визнаєте недійсним кешований вимога, щоб перевірити це належним чином.

Наприклад, у наступному не буде заглушено env:

const nodeEnv = process.env.NODE_ENV;

const fnToTest = () => {
   nodeEnv ...
}

3
Цей процес здебільшого спрацював. Мені довелося налаштувати метод "після". after(() => { process.env = Object.assign({}, env); }); В іншому випадку тести маніпулюють спільною копією. Потрібно встановити після кожного тесту свіжу версію.
Кайл

1
@Kyle .. ні, не було б? за умови, що ви встановили env у верхній частині вашого файлу, він буде відновлений до того, що був на початку вашого тестового набору ..
В'язень

4

У тому spec-helper.coffeeчи іншому схожому місці, де ви налаштовуєте свою пісочницю sinon, слідкуйте за оригіналом process.envта відновлюйте його після кожного тестування, щоб ви не протікали між тестами та не мусили пам’ятати щоразу скидати.

_ = require 'lodash'
sinon = require 'sinon'

beforeEach ->
    @originalProcessEnv = _.cloneDeep process.env

afterEach ->
    process.env = _.cloneDeep @originalProcessEnv

У своєму тесті використовуйте process.envяк зазвичай.

it 'does something based on an env var', ->
    process.env.FOO = 'bar'

underscore«S cloneфункція працює на місці cloneDeep- корисно , якщо ви вже використовуєте , underscoreа не lodash.
Роб

4

За допомогою sinon ви можете заглушити будь-яку подібну змінну.

 const myObj = {
    example: 'oldValue', 
 };

 sinon.stub(myObj, 'example').value('newValue');

 myObj.example; // 'newValue'

Цей приклад - форма документації sinon. https://sinonjs.org/releases/v6.1.5/stubs/


Завдяки цим знанням ви можете заглушити будь-яку змінну середовища. У вашому випадку це буде виглядати так:

 let stub = sinon.stub(process.env, 'FOO').value('bar');

5
Я отримав повідомлення про помилку "Не вдається заглушити неіснуюче власне властивість FOO". Також використовую wallaby.js, хоча запускаю мої тести.
Уілл Ловетт,

1
Дякуємо за публікацію відповіді на питання "Як виглядає заглушення env var?" замість того, щоб просто казати, що нам не потрібно, тому що ми можемо ними маніпулювати вручну :)
Буде

У мене була та ж помилка, що і @WillLovett, і я її вирішив, додавши виклик require у верхній частині мого скрипта модульного тесту: require('dotenv').config();я зрозумів, що це зазвичай викликається під час запуску мого додатка, але якщо я запускаю свої модульні тести безпосередньо, це виписка вимагатиметься.
Фон Піттман,

4

Як швидко знущатися над process.env під час модульного тестування.

https://glebbahmutov.com/blog/mocking-process-env/

const sinon = require('sinon')
let sandbox = sinon.createSandbox()

beforeEach(() => {
  sandbox.stub(process.env, 'USER').value('test-user')
})

it('has expected user', () => {
  assert(process.env.USER === 'test-user', 'wrong user')
})

afterEach(() => {
  sandbox.restore()
})

Але як щодо властивостей, які можуть не існувати в process.env до тесту? Ви можете використовувати наступний пакет, і тоді ви зможете перевірити неіснуючі змінні env.

https://github.com/bahmutov/mocked-env


Це не спрацює, якщо значення process.env.USERще не має.
Sohail Si

0

Ви можете використовувати це, якщо хочете заглушити ключ, якого немає в process.env

const sinon = require('sinon')
let sandbox = sinon.createSandbox();
sandbox.stub(process, 'env').value({ 'SOME_KEY': 'SOME_VALUE' });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.