-
-
Notifications
You must be signed in to change notification settings - Fork 771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stubbing constructor does not work #1892
Comments
You’re stubbing a reference to the constructor ( You can inject the constructor and then inject a plain stub in your test to verify that it was called with |
@RenWenshan This issue has appeared multiple times, but it doesn't have anything to do with Sinon in itself, but is simply due to a missing understanding of what the What we as an org can do to improve the situation is to write tutorials and documentation, something that demands a bit of an effort, which is why we have an issue for tackling this (#1121). Until that materializes itself I suggest reading
That knowledge will make it vastly easier to work with your ES6 (and later) code, as you know what is really happening. |
@fatso83 thank you so much for explaining this. Now I see that My original need was to stub the constructor of a class's parent class so I can test whether class Foo {
constructor() {
console.log("Foo");
}
}
class FooBar extends Foo {
constructor() {
super();
console.log("FooBar");
}
} Since the underlying implementation of Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; I think I can stub the const stub = sinon.stub(FooBar, '__proto__').callsFake(() => {
console.log("stub");
});
const foo = new FooBar(); // still outputs "Foo\nFooBar" |
Your thinking is sound, but the implementation uses deprecated elements.
Basically, you shouldn't use it in your code. There is a reason the
See this gist for more. Also this in case you wonder about ES5 inheritance. |
@fatso83 Thanks for the gist. That helped me stubbing classes. it('test sinon constructor spy with container', () => {
const testClassContainer = {};
testClassContainer.TestClass = class TestClass {
constructor() {
console.log('testClass created');
}
}
const a = sinon.spy(testClassContainer, 'TestClass');
console.log('called', a.called); // false
new testClassContainer.TestClass();
console.log('called', a.called); // true
}); |
That looks like a usage question; please post it to StackOverflow and tag it with A lot more people follow that tag that will help you. |
Here's what works for me: test('constructor', async () => {
const constructorStub = sinon.stub()
function MyClass (...args) {
return constructorStub(...args)
}
new MyClass({ some: 'args' })
sinon.assert.calledWith(constructorStub, { some: 'args' })
}) |
@simoneb Are you sure that even makes sense simon? You just implemented the entire object to test as something that returns a stub. That is something that is not possible/makes sense in any production system. This is not "stubbing the constructor", btw. This is creating a constructor that returns a function and testing if the returned function is called. The constructor is still |
Yes this is not stubbing the constructor but when used in conjunction with something like proxyquire, which you can use to mock module exports, you can replace the constructor of an external library with |
How about replacing the entire class as a stub instead? import sinon from 'sinon';
import * as exampleModule from 'exampleModule';
describe('example', function(){
it(function() {
const classStubbedInstance = Sinon.createStubInstance(exampleModule.ExampleClass);
const constructorStub = Sinon.stub(module, 'ExampleClass').returns(classStubbedInstance);
sinon.assert.calledWith({some: 'args'})
})
) So far it's worked for some simple cases for me. |
@Idono87 what is "module" in this case? |
I really don't know what your asking. What is a module? What module am i referencing? |
@Idono87 |
Missed that. It's just a typo. Should be "exampleModule". |
@fatso83 This code works, but is it still the way sinon users should do it? Namely, has this been integrated into the sinon API? e.g., |
@DanKaplanSES I initially loved this approach and it does work. But actually the routing to callsFake persists even after the restore call on the sandbox (in my case I use sinon sandbox). So the Object.setPrototypeOf has to be used and reset separately in addition to restoring the stub/sandbox. It's not actually stubbing the constructor here but replacing the prototype with a new function. It's similar to calling Object.setPrototypeOf(B, function(){console.log('....');}) which works without the stub. |
Yeah, I think it has room for improvement so I created #2578 |
Describe the bug
Doesn't trigger stubbed constructor
To Reproduce
Run the following test, it will give
AssertError: expected constructor to be called once but was called 0 times
:Expected behavior
First test passes (stubbed constructor gets called)
Screenshots
If applicable, add screenshots to help explain your problem.
Context (please complete the following information):
The text was updated successfully, but these errors were encountered: