Wie stub prozess.env in node.js?

81

Ich möchte Stummel process.env.FOOmit bar.

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

Ich bin verwirrt. Ich lese das Dokument, verstehe es aber noch nicht. sinonjs docs

sinonjs ist ein Beispiel, nicht sinonjs ist in Ordnung.

Matt - Sanemat
quelle
Können Sie erklären, warum Sie Umgebungsvariablen stubben möchten? Tun Sie dies unter einem Unix-ähnlichen Betriebssystem oder Windows?
Slebetman
1
@slebetman Es ist üblich, sich bei der Konfiguration auf Umgebungsvariablen zu verlassen, z. B. einen API-Schlüssel für einen Dienst, auf den Sie sich verlassen. Siehe 12factor.net .
Andrew Homeyer
1
@ AndrewHomeyer: Ja, aber Sie stub sie nicht - Sie stellen sie richtig für den Test ein
Slebetman

Antworten:

74

Nach meinem Verständnis process.envkönnen Sie es beim Festlegen seiner Eigenschaften einfach wie jede andere Variable behandeln. Beachten Sie jedoch, dass jeder Wert in process.enveine Zeichenfolge sein muss. Wenn Sie also einen bestimmten Wert in Ihrem Test benötigen:

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

Stellen Sie sicher, dass Sie die Variable auf ihren ursprünglichen Wert zurücksetzen oder ganz löschen, um zu vermeiden, dass der Status in andere Tests verloren geht:

   afterEach(() => {
       delete process.env.NODE_ENV;
   });
Joshua Dutton
quelle
8
Für mich geht das. Beachten Sie, dass Sie beim Testen eines Moduls, das NODE_ENV beim ersten Laden des Moduls liest, wahrscheinlich NODE_ENV vor dem Laden des Moduls festlegen möchten (dh NODE_ENV kann in einem beforeEach-Block festgelegt werden). Dies kann offensichtlich erscheinen , aber es hat mich schon einmal gestolpert.
Terrence
Wenn Sie Probleme haben, können Sie ein Code-Snippet veröffentlichen, das jemand ansehen kann? Ich habe meine Antwort unter Berücksichtigung der Syntax des Mocha-Testläufers geschrieben, aber sie sollte auch mit jedem anderen Läufer (z. B. Labor) funktionieren.
Joshua Dutton
2
Das funktioniert, aber ich habe bei der Verwendung eine Eigenart gefunden jest. In meinem Produktionscode habe ich von env einer const zugewiesen (zB const X = process.env.X). Die const wurde im (ES) Modulbereich deklariert, nicht im Funktionsbereich. Meine Tests haben bei jest --watchwiederholten Testläufen immer bestanden , sind aber beim ersten Lauf immer fehlgeschlagen. Es gibt ein Bestellproblem, das ich hier nicht vollständig verstehe. Stellen Sie einfach sicher, dass Sie immer direkt aus process.envIhrem Produktionscode (dh in einer Funktion) lesen und ihn nicht auf Modulebene zwischenspeichern.
Jesse Buchanan
1
Dies funktioniert gut, wenn Sie die Datei process.env in einer Funktion auswerten, jedoch nicht, wenn es sich um eine Konstante handelt. Zum Beispiel const myValue = process.env.value ? process.env.value : 'default'würde ich nicht funktionieren, wenn Sie process.env.value innerhalb eines Tests festlegen. Funktioniert jedoch const myValue = () => (process.env.value ? process.env.value : 'default'wie erwartet!
Rafael Marques
In diesem Sinne hatte ich: const SWITCH_ON = (process.env.SWITCH_ON.toLowerCase() === 'true');was nicht funktionierte, also änderte ich es in zwei Zeilen: var switchOn = process.env.SWITCH_ON; const SWITCH_ON = (switchOn === undefined ? false : switchOn.toLowerCase() === 'true');Die Initiale gab mir immer wieder undefinedFehler, wo ich die.toLowerCase()
Scala Enthusiast
25

Ich konnte process.envin meinen Unit-Tests richtig geklubbt werden, indem ich es klonte und in einer Teardown-Methode wiederherstellte.

Beispiel mit Mokka

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

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

...

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

Beachten Sie, dass dies nur funktioniert, wenn process.env nur in der von Ihnen getesteten Funktion gelesen wird. Wenn der zu testende Code beispielsweise die Variable liest und in einem Abschluss verwendet, funktioniert dies nicht. Sie machen wahrscheinlich die zwischengespeicherte Anforderung ungültig, um dies ordnungsgemäß zu testen.

Zum Beispiel wird die Umgebung nicht wie folgt blockiert:

const nodeEnv = process.env.NODE_ENV;

const fnToTest = () => {
   nodeEnv ...
}
Bitte
quelle
3
Dieser Prozess hat meistens funktioniert. Ich musste die "After" -Methode optimieren. after(() => { process.env = Object.assign({}, env); }); Andernfalls würden die Tests die freigegebene Kopie manipulieren. Müssen Sie nach jedem Test eine neue Version einstellen.
Kyle
1
@ Kyle .. nein würde es nicht? Vorausgesetzt, Sie richten env einmal oben in Ihrer Datei ein, wird es auf den Stand zu Beginn Ihrer Testsuite zurückgesetzt.
Prisoner
4

spec-helper.coffeeBehalten Sie in einem oder einem ähnlichen Bereich, in dem Sie Ihre Sinon-Sandbox eingerichtet haben, den Überblick über das Original process.envund stellen Sie es nach jedem Test wieder her, damit Sie nicht zwischen den Tests auslaufen und nicht jedes Mal daran denken müssen, es zurückzusetzen.

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

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

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

Verwenden Sie in Ihrem Test process.envwie gewohnt.

it 'does something based on an env var', ->
    process.env.FOO = 'bar'
Andrew Homeyer
quelle
underscoreDie cloneFunktion von funktioniert anstelle von cloneDeep- nützlich, wenn Sie bereits underscoreanstatt verwenden lodash.
Rob
4

Mit sinon können Sie jede Variable wie diese stubben.

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

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

 myObj.example; // 'newValue'

Dieses Beispiel ist eine Sinon-Dokumentation. https://sinonjs.org/releases/v6.1.5/stubs/


Mit diesem Wissen können Sie jede Umgebungsvariable stubben. In Ihrem Fall würde es so aussehen:

 let stub = sinon.stub(process.env, 'FOO').value('bar');
Getriax
quelle
5
Ich habe die Fehlermeldung "Nicht existierende eigene Eigenschaft FOO kann nicht gestoppt werden" erhalten. Ich benutze aber auch wallaby.js, um meine Tests auszuführen.
Will Lovett
1
Vielen Dank für die Antwort auf die Frage "Wie sieht das Stubben eines env var aus?" anstatt nur zu sagen, dass wir das nicht müssen, weil wir sie manuell manipulieren können :)
Will
Ich hatte den gleichen Fehler wie @WillLovett und habe ihn behoben, indem ich den erforderlichen Aufruf oben in meinem Unit-Test-Skript hinzugefügt habe: require('dotenv').config();Ich habe festgestellt, dass dies normalerweise aufgerufen wird, wenn meine Anwendung ausgeführt wird, aber wenn ich meine Unit-Tests direkt ausführe, dies require-Anweisung würde fehlen.
Von Pittman
4

Wie man process.env während des Unit-Tests schnell verspottet.

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()
})

Aber was ist mit Eigenschaften, die vor dem Test möglicherweise nicht in process.env vorhanden sind? Sie können das folgende Paket verwenden und dann die nicht vorhandenen env-Variablen testen.

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

Hossein Rabizadeh
quelle
Dies funktioniert nicht, wenn process.env.USERnoch kein Wert vorhanden ist.
Sohail Si