Skip to content
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

Restore a specific mock/spy #9

Closed
thislooksfun opened this issue Nov 29, 2015 · 6 comments
Closed

Restore a specific mock/spy #9

thislooksfun opened this issue Nov 29, 2015 · 6 comments

Comments

@thislooksfun
Copy link

Hello! First off, I love this tool. I took one look at sinon and instantly sought a more intuitive method, and I wound up finding this! I only have one request, which is a restore() function on individual mocks. In my tests I'm finding myself needing to mocks for one method call that need to be undone before the next one, and I would like a way to not have to redo all the other mocks and spies.

Proposed format:

simple = require("simple-mock")

simple.mock(console, "log")
mockDir = simple.mock(object, "key", "new information")
do_something()
mockDir.restore()
// console.log is still being spied on
@jupiter
Copy link
Owner

jupiter commented Jan 6, 2016

Hey, sorry I missed this issue.

In this particular example, the mockDir.restore() API would not be possible due to mockDir being a string. There are some tricks we can pull, but I prefer to keep it as clean as possible. The only other option is to not return the mocked value, but to return the reference to the mock. This would be a problem for chaining on function mocks, so we'd have to return something different for value mocks vs function mocks. This would work, but it could be a breaking change for some, which could be painful, however rare this may be. Do you have any ideas on how you'd want to implement it?

I usually try to keep shared setup for subsequent tests in something such as a beforeEach block or just a setup function.

@thislooksfun
Copy link
Author

So, correct me if I'm wrong: the problem is that currently the simple.mock function returns the object that is being replaced, and you (understandably) don't want to change that because it would break existing setups?

@jupiter
Copy link
Owner

jupiter commented Jan 22, 2016

Correct. This behaviour enables you to chain behaviour instructions, e.g.

simple.mock(object, 'key')
.returnWith('something')
.throwWith(new Error('already returned')`

I do realise that the case for simple value substitution, i.e. not a method mock, does not benefit from chaining anyway. Would an API such as simple.restore(object, 'key') be good?

@thislooksfun
Copy link
Author

That method could work, but I'm worried about multiple mocks replacing the same value.
I've been playing around a bit, but so far I have been unable to come up with a good way to keep the string and still add a restore function, but I believe the chaining problem can be easily solved by adding the restore function to the mock. It doesn't have to be chainable itself, because why would you want to call something else after it, but it can go somewhere in here

My work so far:

var str = "hi";

var strWithRestore = Object(str);

strWithRestore.restoreMock = function() {
  return console.log("Hello!");
};

var testing = {
  hi: "1",
  hello: "2"
};

testing[str];  // Gives '1'
testing[strWithRestore];  // Still gives '1'
typeof strWithRestore == "string"  // Doesn't work, returns 'object'

@jupiter
Copy link
Owner

jupiter commented Jan 26, 2016

That's perhaps a bit too clever, changing to a string object.

I've implemented the simple.restore(object, 'key') method in the above commit. This should not break any existing APIs and is even safe if you mock a value multiple times - it will only restore the last mocked value.

jupiter added a commit that referenced this issue Jan 26, 2016
Add granular mock restore to resolve #9
@thislooksfun
Copy link
Author

Awesome, thanks! My confusion about conflicting mocks was that I, for whatever silly reason, thought you meant to implement it like so:

mockDir = simple.mock(object, "key", "new information")
do_something()
simple.restore(mockDir)

Which would fail if mockDir was the same string as any other mock. I now understand what you actually meant by that, and I have to say, that's a very nice solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants