Sinon: Ist es möglich, eine eigenständige Dienstprogrammfunktion zu stoppen?

Erstellt am 12. Sept. 2014  ·  18Kommentare  ·  Quelle: sinonjs/sinon

Viele Knotenmodule exportieren eine einzelne Funktion (keine Konstruktorfunktion, sondern eine Allzweck-"Dienstprogramm"-Funktion) als ihre "module.exports". Ist es möglich, Sinon.js zu verwenden, um diese eigenständige Funktion zu stoppen?

// some module, "sum.js" that's "required" throughout the application
module.exports = function(a, b) {
    return a + b;
};

// test.js
var sum = require('sum');
...

beforeEach(function() {
    sumStub = sinon.stub(sum);
    // throws: TypeError: Attempted to wrap undefined property undefined as function
});

afterEach(function() {
   sumStub.restore();
});
...

Gibt es eine Möglichkeit, dies zu erreichen?

Hilfreichster Kommentar

Versuche dies

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

Alle 18 Kommentare

Leider nicht.

Für npm können Sie https://github.com/thlorenz/proxyquire oder ähnliches verwenden. Michael Feathers würde dies eine Verbindungsnaht nennen .

Es ist nicht elegant, aber machbar.

Sobald Sie das eingerichtet haben, können Sie Sinon wie gewohnt verwenden.

Auf lange Sicht möchten Sie Ihre Architektur vielleicht in Richtung _Objektnähte_ verlagern, aber es ist eine Lösung, die heute funktioniert. Ähnliche Projekte existieren für RequireJS.

function MyFunction(){}
module.exports = function(){ return module.exports.MyFunction.apply(this, arguments) }
module.exports.MyFunction = MyFunction

Dann können Sie require('./MyFunction').MyFunction stubieren und der Rest Ihres Codes wird ohne Änderung die gestubte Edition sehen.

:dizzy: :dizzy_face: :dizzy:

Ich bin neulich über das Gleiche gestolpert und habe Folgendes getan:

const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()

const ModuleWithDependency = proxyquire('module', {
  'sum': sum
})

funktioniert für unseren Fall ganz gut.

Bei Verwendung von CommonJS:

const myStubbedModule = function( absoluteModulePath ) {
  const stub = sinon.stub();
  require.cache[ require.resolve( absoluteModulePath ) ] = stub;
  return stub;
}

_Hinweis_: Je nachdem, ob Sie transpilieren, müssen Sie möglicherweise Folgendes tun:

require.cache[ require.resolve( absoluteModulePath ) ] = {
  default: stub,
  exports: stub
}

Während der Tests muss ich oft einen Stub für einen bestimmten Test einfügen. Der Wrapper-Funktions-Ansatz, den ich gewählt habe, ermöglicht es mir, die Codebasis zu ändern und meine Stubs einzufügen, wann immer ich möchte, ohne entweder einen Stub-First-Ansatz wählen oder mit Modulen mit Verweisen auf die anderen Module, die ich versuche, whack-a-mole spielen zu müssen Stub und ersetzen-in-Place.

Ich hatte eine Reihe von Code-Reviews, bei denen mich Leute dazu gedrängt haben, über proxyquire, mock-require usw während des Testaufbaus an Ort und Stelle benötigt. Mit proxyquire kann man zumindest eine mikro-/fixture-große Version der App proxyquire(), eine Top-Level-Version, und alle Stubs werden während des Ladens eingebracht, aber dies auf JS-Sprachebene statt auf Node-Modul-Ebene anzugehen, geht weiter mir deutlich einfacher und leichter durchgängig und gefahrlos zu handhaben (Vorbehalt: solange man sich an die Wiederherstellung erinnert).

Ich habe dieses Modul zu einfacheren Stub-Modulen gemacht https://github.com/caiogondim/stubbable-decorator.js

Ich habe gerade mit Sinon gespielt und eine einfache Lösung gefunden, die zu funktionieren scheint - fügen Sie einfach "Argumente" als zweites Argument hinzu

const sumStub = sinon.stub(sum, 'arguments');
sumStub.withArgs(2, 2).returns(4);
sumStub.withArgs(3, 3).returns(6);

Versuche dies

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

@harryi3t - danke, das hat bei mir funktioniert.

@harryi3t Das hat bei mir mit ES-Modulen nicht funktioniert.
Fehler: can't redefine non-configurable property "default"

@elliottregan ES-Module sind gemäß STANDARD nicht stubbfähig. Wir haben sogar Tests, die dieses Verhalten ich hier bespreche .

Viele Leute testen nicht wirklich ES-Module, sondern transpilierte ES-Module (mit Webpack/Babel usw.). Der resultierende ES5 verwendet Getter, um die Funktionsweise von ES-Modulen zu emulieren. Vielleicht tust du das, aber versuche den einfachen Weg, den ich im verlinkten Thread vorschlage. mocha --register ... bringt dich weit.

Mögliche Problemumgehung

(function (defineProperty) {
    Object.defineProperty = (obj, prop, desc) => {
        desc.configurable = true;
        return defineProperty(obj, prop, desc);
    };
})(Object.defineProperty);

@Sujimoshi Workaround für was genau? Was ist der Kontext für Ihren Fix? Und wo würden die Leute die Lösung platzieren? In seiner aktuellen Inkarnation fehlen ihm ein bisschen zu viele Informationen, um hilfreich zu sein. Es würde der ursprünglichen Frage nicht helfen und funktioniert nicht für ES-Module . Ich vermute, dass es sich um Code handelt, der von Webpack 4 verarbeitet wurde, da er (je nach Toolchain) auf Code zutreffen könnte, der mit der ES2015+-Syntax geschrieben wurde und in ES5 _transpiliert_ wurde, _emuliert_ die Unveränderlichkeit von ES-Modulen durch nicht konfigurierbare Objektdeskriptoren .

Versuche dies

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

jetzt verworfen.

Ich habe gerade mein ES6-Modul daraus umgeschrieben:

export default const doCoolStuff = () => {
  // do the cool stuff...
}

dazu:

export default {
  doCoolStuff: () => {
    // do the cool stuff...
  }
} 

Es ist ein bisschen klobig, aber es hat mir ermöglicht, die Funktion in einen Stub zu packen.

jetzt ist fast 2021, ist das möglich?

jetzt ist fast 2021, ist das möglich?

Nicht viel anders als 2019.
ES-Module haben sich nicht geändert, CommonJS hat sich nicht geändert, JavaScript hat sich nicht geändert.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen