Stubbing a class method with Sinon.js
Asked Answered
T

4

121

I am trying to stub a method using sinon.js but I get the following error:

Uncaught TypeError: Attempted to wrap undefined property sample_pressure as function

I also went to this question (Stubbing and/or mocking a class in sinon.js?) and copied and pasted the code but I get the same error.

Here is my code:

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

Here is the jsFiddle (http://jsfiddle.net/pebreo/wyg5f/5/) for the above code, and the jsFiddle for the SO question that I mentioned (http://jsfiddle.net/pebreo/9mK5d/1/).

I made sure to include sinon in the External Resources in jsFiddle and even jQuery 1.9. What am I doing wrong?

Throve answered 12/1, 2014 at 6:40 Comment(0)
A
180

Your code is attempting to stub a function on Sensor, but you have defined the function on Sensor.prototype.

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

is essentially the same as this:

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

but it is smart enough to see that Sensor["sample_pressure"] doesn't exist.

So what you would want to do is something like these:

// 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());

or

// 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());

or

// Create a whole fake instance of 'Sensor' with none of the class's logic.
var sensor = sinon.createStubInstance(Sensor);
console.log(sensor.sample_pressure());
Acetyl answered 12/1, 2014 at 19:47 Comment(5)
Which thing is deprecated?Acetyl
sinon.stub(Sensor, "sample_pressure", function() {return 0})Shelbyshelden
That's in my answer because the original question specifically asked about it. Given that my answer doesn't suggest it as the correct approach to begin with, I'm not sure what you're asking me to change. .returns(0) already does the same thing as .callFake(() => 0).Acetyl
It doesn't seem that returns is deprecated. sinonjs.org/releases/v3.0.0/stubs. @danday74, please provide the reference.Toffee
@Shelbyshelden .stub with a function as the third argument is removed: github.com/sinonjs/sinon/blob/master/lib/sinon/stub.js#L17 There is nothing wrong with .returns or .callsFake, so there is nothing wrong with this answer.Acetyl
S
75

The top answer is deprecated. You should now use:

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

Or for static methods:

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

Or for simple cases just use returns:

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

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

Or if you want to stub a method for an instance:

const yourClassInstance = new YourClass();
sinon.stub(yourClassInstance, 'myMethod').returns({})
Shelbyshelden answered 22/7, 2017 at 23:26 Comment(3)
It would be great if you could mention the specific version for your said method when this was added to sinonjs i.e. callsFake() moreover, for the older versions how can this be deprecated?Convoluted
When using ES6 modules: I'm creating the stub of YourClass.get() in a test project. The test calls another module that imports YourClass. Will the module YourClass.get() respect the stub? If not, is there a solution?Rummage
Your solutions work for me. I wish if I give you more points :D Thanks.Georgeta
G
6

I ran into the same error trying to mock a method of a CoffeeScript class using Sinon.

Given a class like this:

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

You can replace its method with a spy this way:

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

# ...

assert.ok(mySpy.called)

Just replace spy with stub or mock as needed.

Note that you'll need to replace assert.ok with whatever assertion your testing framework has.

Girvin answered 23/6, 2017 at 14:14 Comment(0)
R
2

Thanks to @loganfsmyth for the tip. I was able to get the stub to work on an Ember class method like this:

sinon.stub(Foo.prototype.constructor, 'find').returns([foo, foo]);
expect(Foo.find()).to.have.length(2)
Residuary answered 24/10, 2014 at 21:22 Comment(2)
This is a comment. Starts with a thanks to another answer and ends with a duplication of its code.Colchicine
Doesn't look like a duplication -- here there is Foo.prototype.constructor, where as in original answer there is Sensor.prototype. Then again, Foo.prototype.constructor doesn't work for me. :)Gilmour

© 2022 - 2024 — McMap. All rights reserved.