sinon
sinon copied to clipboard
Difficult to "spy on everything except one" with fakes
Describe the bug Let's say I want to spy on all properties of an object using fakes. I might do something like:
const properties = Object.getOwnPropertyNames(o);
const prototypeProperties = Object.getOwnPropertyNames(
Object.getPrototypeOf(o)
);
for (const k of properties.concat(prototypeProperties)) {
const prop = o[k];
if (typeof prop === 'function') {
const fake = sinon.fake(prop);
sandbox.replace(o, k, fake);
}
}
I might later need to override the behaviour of a particular method, but now I can't:
const fake = sinon.fake.rejects('force an error');
sandbox.replace(o, 'method', fake) // TypeError: Attempted to replace method which is already replaced
Expected behavior Replacing the existing method should be possible. I believe the above is a valid counterexample to the contention of 'replacing an already replaced method is a bug in your test code'.
Why wouldn't you just change the behavior instead of replacing with a new one?
Based on your example above: o.method.rejects('force an error')
instead of making an entirely new fake.
Please feel free to reopen this issue if this doesn't solve the problem.
from the fake
docs:
A fake is immutable: once created, the behavior will not change.
am I missing something?
That's my mistake. I have yet to use fake
s myself. I still use stubs and spies directly. Can you just restore that one property before you replace it?
o.method.restore();
const fake = sinon.fake.rejects('force an error');
sandbox.replace(o, 'method', fake);
Honestly I've never restored a part of a sandbox before (instead of all at once), but I'm just tossing out ideas. Alternatively you could use something that is mutable (like spies or stubs) for that replacement instead: Based on your code above:
if (typeof prop === 'function') {
// conditionally use a mutable fake
const fake = k === 'method' ? sinon.stub() : sinon.fake(prop);
sandbox.replace(o, k, fake);
}
Based on the documentation and the code, things seem to be working as expected though. This doesn't seem like a bug or anything is broken. It seems like in this specific case it would be easiest to update the way you're mocking the methods. Let me know if we can help any further.
Can you just restore that one property before you replace it?
Nope, fakes can't restore themselves, you need to do it with the sandbox you used to replace them in the first place. And, as you say, sandboxes can't do a partial restore (because before fakes were added, this wasn't really a requirement because you could just mutate the stub or whatever).
I agree it's not a bug, but it is imo a pretty important requirement to be able to use fake
s in real-world usage. I don't think the suggestion of "don't use fakes" is really adequate. It looks like fake
s were written in order to promote creating immutable mocks (good), but the APIs around using them still seem to have a few holes.
I completely understand. Thanks for your feedback and filing the issue.
@mroderick Check out this fakes feedback.
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.