Kończenie metody klasy za pomocą Sinon.js


99

Próbuję odgiąć metodę przy użyciu sinon.js, ale pojawia się następujący błąd:

Uncaught TypeError: Attempted to wrap undefined property sample_pressure as function

Poszedłem również do tego pytania ( Stubbing i / lub mocking a class in sinon.js? ) I skopiowałem i wkleiłem kod, ale pojawia się ten sam błąd.

Oto mój kod:

Sensor = (function() {
  // A simple Sensor class

  // Constructor
  function Sensor(pressure) {
    this.pressure = pressure;
  }

  Sensor.prototype.sample_pressure = function() {
    return this.pressure;
  };

  return Sensor;

})();

// Doesn't work
var stub_sens = sinon.stub(Sensor, "sample_pressure").returns(0);

// Doesn't work
var stub_sens = sinon.stub(Sensor, "sample_pressure", function() {return 0});

// Never gets this far
console.log(stub_sens.sample_pressure());

Tutaj jest jsFiddle ( http://jsfiddle.net/pebreo/wyg5f/5/ ) dla powyższego kodu i jsFiddle dla pytania SO, o którym wspomniałem ( http://jsfiddle.net/pebreo/9mK5d/1/ ).

I się, że to sinon w Zasoby zewnętrzne w jsFiddle i nawet jQuery 1.9. Co ja robię źle?

Odpowiedzi:


155

Twój kod próbuje włączyć funkcję odgałęzienia Sensor, ale zdefiniowałeś tę funkcję Sensor.prototype.

sinon.stub(Sensor, "sample_pressure", function() {return 0})

jest zasadniczo taka sama jak ta:

Sensor["sample_pressure"] = function() {return 0};

ale jest wystarczająco sprytny, aby zobaczyć, że Sensor["sample_pressure"]nie istnieje.

Więc to, co chciałbyś zrobić, to coś takiego:

// Stub the prototype's function so that there is a spy on any new instance
// of Sensor that is created. Kind of overkill.
sinon.stub(Sensor.prototype, "sample_pressure").returns(0);

var sensor = new Sensor();
console.log(sensor.sample_pressure());

lub

// Stub the function on a single instance of 'Sensor'.
var sensor = new Sensor();
sinon.stub(sensor, "sample_pressure").returns(0);

console.log(sensor.sample_pressure());

lub

// Create a whole fake instance of 'Sensor' with none of the class's logic.
var sensor = sinon.createStubInstance(Sensor);
console.log(sensor.sample_pressure());

1
Która rzecz jest przestarzała?
loganfsmyth

sinon.stub (Sensor, "sample_pressure", function () {return 0})
danday74

To jest w mojej odpowiedzi, ponieważ pierwotne pytanie konkretnie o to zadane. Biorąc pod uwagę, że moja odpowiedź nie sugeruje, że jest to właściwe podejście na początek, nie jestem pewien, o co prosisz mnie o zmianę. .returns(0)już robi to samo co .callFake(() => 0).
loganfsmyth

1
Nie wydaje się, że returnsjest to przestarzałe. sinonjs.org/releases/v3.0.0/stubs . @ danday74, podaj numer referencyjny.
allenhwkim

2
@ danday74 .stubz funkcją jako trzecim argumentem jest usuwana: github.com/sinonjs/sinon/blob/master/lib/sinon/stub.js#L17 Nie ma nic złego w .returnslub .callsFake, więc nie ma nic złego w tej odpowiedzi.
loganfsmyth

52

Najlepsza odpowiedź jest przestarzała. Powinieneś teraz użyć:

sinon.stub(YourClass.prototype, 'myMethod').callsFake(() => {
    return {}
})

Lub w przypadku metod statycznych:

sinon.stub(YourClass, 'myStaticMethod').callsFake(() => {
    return {}
})

Lub w prostych przypadkach użyj zwrotów:

sinon.stub(YourClass.prototype, 'myMethod').returns({})

sinon.stub(YourClass, 'myStaticMethod').returns({})

Lub jeśli chcesz odgiąć metodę dla instancji:

const yourClassInstance = new YourClass();
sinon.stub(yourClassInstance, 'myMethod').returns({})

4
Byłoby wspaniale, gdybyś mógł wspomnieć o konkretnej wersji tej metody, gdy została dodana, sinonjstj. callsFake()Ponadto, w przypadku starszych wersji, jak można ją wycofać?
aitchkhan

3
Podczas korzystania z modułów ES6: tworzę kod pośredniczący YourClass.get () w projekcie testowym. Test wywołuje inny moduł, który importuje YourClass. Czy moduł YourClass.get () będzie przestrzegać kodu stub? Jeśli nie, czy istnieje rozwiązanie?
Learner

1
Twoje rozwiązania działają dla mnie. Chciałbym dać ci więcej punktów: D Dzięki.
Rubel hasan

5

Napotkałem ten sam błąd, próbując wyszydzić metodę klasy CoffeeScript przy użyciu Sinon.

Biorąc pod uwagę taką klasę:

class MyClass
  myMethod: ->
    # do stuff ...

Możesz zastąpić jego metodę szpiegiem w ten sposób:

mySpy = sinon.spy(MyClass.prototype, "myMethod")

# ...

assert.ok(mySpy.called)

Wystarczy wymienić spyz stublub mockw miarę potrzeb.

Zauważ, że będziesz musiał zastąpić to, assert.okco masz w swojej strukturze testowej.


2

Dzięki @loganfsmyth za wskazówkę. Udało mi się zmusić kodowanie do pracy z metodą klasy Ember w następujący sposób:

sinon.stub(Foo.prototype.constructor, 'find').returns([foo, foo]);
expect(Foo.find()).to.have.length(2)

3
To jest komentarz. Rozpoczyna się podziękowaniem za inną odpowiedź, a kończy skopiowaniem jej kodu.
michelpm

5
Nie wygląda na powielenie - oto jest Foo.prototype.constructor , tak jak w oryginalnej odpowiedzi Sensor.prototype. Z drugiej strony, Foo.prototype.constructordla mnie nie działa. :)
shaunc
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.