Sinon: createStubInstance does not stub own properties or anything inherited

Created on 23 Jan 2021  ·  3Comments  ·  Source: sinonjs/sinon

Describe the bug
createStubInstance ignores own properties and, on a super class, is blind to its inherited methods and properties

To Reproduce

class SubTest {
  name;

  constructor({ name }) { this.name = name }

  something() {}
}

export default class SuperTest extends SubTest {
  description;

  constructor(...props) {
    super(props);
    this.description = props.description;
  }

  noop() {}
}
import sinon from 'sinon';
import SuperTest from './SuperTest.js';

sinon.createStubInstance(SuperTest, {
  description: 'Lorem Ipsum',
  name: 'Foobar',
  noop() {},
  something() {},
});
Error: Cannot stub description. Property does not exist!
    at …/sinon/lib/sinon/stub.js:129:19
    at Array.forEach (<anonymous>)
    at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)

after commenting out description: 'Lorem Ipsum',:

Error: Cannot stub name. Property does not exist!
    at …/sinon/lib/sinon/stub.js:129:19
    at Array.forEach (<anonymous>)
    at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)

after also commenting out name: 'Foobar',:

Error: Cannot stub something. Property does not exist!
    at …/sinon/lib/sinon/stub.js:129:19
    at Array.forEach (<anonymous>)
    at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)

With only noop() {} in the overrides, it works.

Expected behavior
I expect createStubInstance to stub any/all fields that exist on the provided class.

Context (please complete the following information):

  • Library version: [email protected]
  • Environment:
    macOS 11.1
    node 15.6.0
    npm 7.4
  • Other libraries you are using:
    chai 4.2.0
    sinon-chai 3.5.0

EDIT: I originally over-simplified the above test and omitted super(), but it had no effect on sinon's behaviour. Test above is corrected.

Easy Documentation Help wanted

All 3 comments

Thanks for bringing this up. There are several things wrong or being misunderstood here:

  • The second argument on createStubInstance isn't documented (I wasn't even aware of it 😄).
  • The documentation explicitly states that

    The given constructor function is not invoked.

    So the assumption that it can be used to pass initial arguments can not work.

  • The existing implementation of this undocumented feature does this:

    • Throws if the property is not overridable because it doesn't exist on the stub instance. This is what happens in your case. The constructor has not been called and therefore your "member" properties do not exist.

    • If a given override is a stub, replace the default stub with the given one (e.g. { something: sinon.stub() }).

    • Otherwise make the default stub return the given property value (e.g. { something: 42 }).

This clearly needs better documentation, but it's not a bug.


How you can make your use case work:

Note that you're creating a new object from the "class" prototype. You're not actually making an instance of the class because the constructor isn't called. Basically the return value of createStubInstance just has the same interface as your class with all functions being replaced with stubs. Therefore, if you need properties on this stub instance, you can just assign them.

thanks for your quick answer!

Note that you're creating a new object from the "class" prototype. You're not actually making an instance of the class because the constructor isn't called. Basically the return value of createStubInstance just has the same interface as your class with all functions being replaced with stubs. Therefore, if you need properties on this stub instance, you can just assign them.

Might it be worthwhile to support that within createStubInstance?

function createStubInstance (…) {
  // …
  return Object.assign(stubbedInstance, propertyValuePairs); // anything it doesn't recognise
}

@jshado1 Sure, we could do that. If you're interested in this feature, you're welcome to send a pull request 🙂

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pavelkornev picture pavelkornev  ·  4Comments

akdor1154 picture akdor1154  ·  4Comments

tinganho picture tinganho  ·  3Comments

byohay picture byohay  ·  3Comments

stevenmusumeche picture stevenmusumeche  ·  3Comments