during block for mocha
-
Ken Collins
Interesting, I might use this. It does seem very useful when you need discreet stubs during a long running test typically in integration/functional land. Possibly a bad pattern in unit land, not sure and moot since you cant make people write good tests with good tools :)
All in all, I like this a lot. My only technical feedback would be to ask if the &block var is needed? Isn't it better practice to only use that var if it is really needed to yield (no pun) better performance.
-
Deleted User
I use this in rspec tests, mostly. It's also useful if you want to have part of a test say that "now" is 2 weeks ago, then 1 week ago, then really now.
As for the &block, I didn't know you could yield without one! In either case, it seems like the only real use for during is with a block -- may as well make it explicit?
Thanks to James for putting this where I should have in the first place!
-
Ken Collins
Yea, totally can without.
def blocked puts 'before' yield puts 'after' end blocked do puts 'doing' end # >> before # >> doing # >> after -
Josh Clayton
Outside of stubbing Time, are there any decent use cases? I can't think of any. If this is what you're going for, why not use a library built specifically for this? Timecop is awesome and will do exactly what you're discussing:
Timecop.freeze("10/1/2009".to_date) do Time.now # Thu Oct 01 00:00:00 -0400 2009 Time.now.advance(:days => 3) # Sun Oct 04 00:00:00 -0400 2009 Date.today # Thu, 01 Oct 2009 end Time.now # Wed Jul 28 08:40:31 -0400 2010If you're using Cucumber, you can add something like this:
# in features/step_definitions/time_steps.rb Given /^today is "([^\"]*)"$/ do |date_time| Timecop.freeze Time.parse(date_time) end After { Timecop.return }What this allows you to do is declare a step that essentially freezes time; in the
Afterblock, Timecop removes all time stubs so you're properly reset to the correct time after each scenario.Hopefully this helps!
-
Deleted User
Right - so the only reason (IMHO) that timecop exists is because these few lines of code are missing from Mocha. Why perpetuate the need for yet another gem?
Other examples: the mind boggles. Any Ruby System level class springs to mind. You want File.open("file that should never be missing", r) to fail? Here you go. You want Tempfile.new to return a specific file at a specific path so you can check the contents? Sure. You want a singleton that's used to access an external service to act like it is missing, but only briefly? Why not.
-
Josh Clayton
Those are great examples of stubbing, but why would you only need a stub for part of that test? Are you familiar with Mocha's
then? This can be used to achieve the same thing; return something the first timeFile.openis called, then return another result, just like it sounds and exactly what you're describing here. For testing external services, what about Fakeweb? Sham Rack? The possibilities are endless! Making Mocha the "end all be all" of stubbing/mocking isn't the solution, especially when these solutions exist in other gems.Also, I'd suggest looking at Timecop's source - the library is definitely not "a few lines of missing code". Another point I'd like to bring up is that if a decent developer is using Mocha for mocking/stubbing, he's probably writing integration tests (likely with Cucumber). Many (if not most) apps (or gems) deal with time, so Cucumber scenarios become easier to write with Timecop; it's almost a given that it's included in every app I develop.
Anyways, I don't want to get into an argument about how to test or anything; I'm just explaining that what it sounds like you're trying to accomplish outside of Time already exists in Mocha (
then) and Timecop exists for times/dates. If the solutions to these issues already exist, why add more code to a library? -
Deleted User
during seems like a reasonable and simple solution to the general problem that is:
"it is hard to unstub"then is a fine solution if you're not worried about "then(be normal)", which seems hard to do with mocha.
Timecop could be huge - I don't know, and I really don't care. Though I don't see why it should be huge - given a couple of trivial changes in Mocha. In fact it ought to be tiny. Seriously - it should be trivial to get mocha to do
Something.stub(:method).returns(my_value).during { ... }
or
Something.stub(:method).returns(my_value)
... Something.unstub(:method)But it isn't. Which is not to say that it's a lot of code - it's just a few lines of super-obscure undocumented code.
I'd like to fix something that I think is missing in Mocha - with just a few lines of code. In fact, I've already fixed it for myself with a monkey patch. And I know there are others (just google a little bit and you'll see - or I can provide references) who want to do the same kind of thing. What can I say - I'm a sharing kinda guy.
-
James Mead
Thanks for all the discussion on this ticket. I think everyone has made some good points.
I agree that it should be easier to "unstub" a method. I thought there was already a ticket for this, but it seems not. I'm going to create one [1]. I've added some questions in there that it would be great to have feedback on.
I think it should be possible to do something like the "during" functionality with the existing Mocha::API#states [2] functionality. However, since this functionality is significantly more flexible than the "during" concept it is inevitably more verbose. I can see an argument for providing a shortcut way of doing it, but I'm pondering whether it belongs in the "core" of Mocha - I'm not sure it does. I'm thinking pretty seriously of trying to separate out a "core" part of Mocha with useful extension points.
Whatever happens, any change will need to be accompanied by a set of acceptance tests.
Cheers, James.
[1] #69 Allow unstubbing of methods [2] http://mocha.rubyforge.org/classes/Mocha/API.html#M000006
-
Deleted User
I agree that this is a better solution. With a solid #unstub in place, #during becomes trivial to write.
The reason I suggested #during is specifically because the API used was obscure, and because a 'real' solution for unstub was outside the scope of work I was willing to undertake to solve my particular problem.
Thanks for being a good shepherd!
-
James Mead
I've added "unstub" functionality.
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.