Fair enough. Thanks.
On Fri, Jul 25, 2008 at 8:53 AM, David Chelimsky <[EMAIL PROTECTED]> wrote: > On Fri, Jul 25, 2008 at 8:49 AM, David Chelimsky <[EMAIL PROTECTED]> wrote: >> On Fri, Jul 25, 2008 at 8:44 AM, Matt Lins <[EMAIL PROTECTED]> wrote: >>> On Fri, Jul 25, 2008 at 8:40 AM, David Chelimsky <[EMAIL PROTECTED]> wrote: >>>>> On Fri, Jul 25, 2008 at 8:15 AM, David Chelimsky <[EMAIL PROTECTED]> >>>>> wrote: >>>>>> On Fri, Jul 25, 2008 at 7:57 AM, David Chelimsky <[EMAIL PROTECTED]> >>>>>> wrote: >>>>>>> On Fri, Jul 25, 2008 at 12:34 AM, Matt Lins <[EMAIL PROTECTED]> wrote: >>>>>>>> On Fri, Jul 25, 2008 at 12:25 AM, Scott Taylor >>>>>>>> <[EMAIL PROTECTED]> wrote: >>>>>>>>> >>>>>>>>> On Jul 25, 2008, at 1:15 AM, Matt Lins wrote: >>>>>>>>> >>>>>>>>>> On Thu, Jul 24, 2008 at 11:47 PM, Scott Taylor >>>>>>>>>> <[EMAIL PROTECTED]> wrote: >>>>>>>>>>> >>>>>>>>>>> On Jul 25, 2008, at 12:32 AM, Matt Lins wrote: >>>>>>>>>>> >>>>>>>>>>>> I suppose the way I'm defining the stubs, differs from what Dave is >>>>>>>>>>>> doing in his example. >>>>>>>>>>>> >>>>>>>>>>>> I assumed that: >>>>>>>>>>>> >>>>>>>>>>>> MyModel = mock('MyModel Class', :count => 1) >>>>>>>>>>>> >>>>>>>>>>>> was the same as: >>>>>>>>>>>> >>>>>>>>>>>> MyModel.stub!(:count).and_return(1) >>>>>>>>>>> >>>>>>>>>>> Nope. Not even close. Here's an equivalent of the first form: >>>>>>>>>>> >>>>>>>>>>> Object.send :remove_const, :MyModel >>>>>>>>>>> MyModel = <a mock object> >>>>>>>>>>> >>>>>>>>>>> and here's the second form: >>>>>>>>>>> >>>>>>>>>>> MyModel.instance_eval do >>>>>>>>>>> def count >>>>>>>>>>> 1 >>>>>>>>>>> end >>>>>>>>>>> end >>>>>>>>>>> >>>>>>>>>>> (or:) >>>>>>>>>>> >>>>>>>>>>> MyModel.class_eval do >>>>>>>>>>> class << self >>>>>>>>>>> def count; 1; end >>>>>>>>>>> end >>>>>>>>>>> end >>>>>>>>>>> >>>>>>>>>>> Scott >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> But the stubs are defined the same way in both occurrences, no? >>>>>>>>>> >>>>>>>>>> MyModel = mock('MyModel Class', :count => 1) >>>>>>>>>> >>>>>>>>>> By passing {:count => 1} to +stubs_and_options+ I should have defined >>>>>>>>>> stubs on the mock object. I'm using it as a shortcut for this: >>>>>>>>>> >>>>>>>>>> MyModel = mock('MyModel Class') >>>>>>>>>> MyModel.stub!(:count).and_return(1) >>>>>>>>>> >>>>>>>>>> If those example aren't doing the exact same thing I guess I'm a >>>>>>>>>> little baffled (or maybe just need to go to sleep). >>>>>>>>> >>>>>>>>> The first one is redefining the constant 'MyModel'. The second one >>>>>>>>> is just >>>>>>>>> redefining a class method (the constant isn't changing - it's >>>>>>>>> remaining >>>>>>>>> whatever it was before - say, a class) >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> But, I'm starting to think they are not. I haven't looked at the >>>>>>>>>>>> rSpec internals to verify, other than the parameter name: >>>>>>>>>>>> >>>>>>>>>>>> stubs_and_options+ lets you assign options and stub values >>>>>>>>>>>> at the same time. The only option available is :null_object. >>>>>>>>>>>> Anything else is treated as a stub value. >>>>>>>>>>>> >>>>>>>>>>>> So, is this problem? >>>>>>>>>>> >>>>>>>>>>> Yeah - so here are two related, but not equivalent ideas: mock >>>>>>>>>>> objects, >>>>>>>>>>> and >>>>>>>>>>> stubs. A stub is just a faked out method - it can exist on a mock >>>>>>>>>>> object >>>>>>>>>>> (a >>>>>>>>>>> completely fake object), or on a partial mock (i.e. a real object, >>>>>>>>>>> with a >>>>>>>>>>> method faked out). mock('My mock") is a mock object, >>>>>>>>>>> MyRealObject.stub!(:foo) is a real object with the method foo faked >>>>>>>>>>> out. >>>>>>>>>>> >>>>>>>>>>> What is the difference between a mock object and a fake object? A >>>>>>>>>>> mock >>>>>>>>>>> object will complain (read: raise an error) any time it receives a >>>>>>>>>>> message >>>>>>>>>>> which it doesn't understand (i.e. one which hasn't been explicitly >>>>>>>>>>> stubbed). >>>>>>>>>>> A real object will work as usual. (A null object mock is a special >>>>>>>>>>> type >>>>>>>>>>> of >>>>>>>>>>> mock - one which never complains. For now, you shouldn't worry >>>>>>>>>>> about >>>>>>>>>>> it). >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Ok, I get what you saying, but as I understand it I am explicitly >>>>>>>>>> stubbing out the methods on the _mock_ object and it's still >>>>>>>>>> complaining. If +stubs_and_options+ isn't stubbing, then what is it >>>>>>>>>> doing? >>>>>>>>> >>>>>>>>> That's right - the hash to the mock method is a shorthand. So these >>>>>>>>> two are >>>>>>>>> equivalent: >>>>>>>>> >>>>>>>>> my_mock = mock('a mock') >>>>>>>>> my_mock.stub!(:foo).and_return(:bar) >>>>>>>>> >>>>>>>>> AND: >>>>>>>>> >>>>>>>>> my_mock = mock("a mock", {:foo => :bar}) >>>>>>>>> >>>>>>>>> Scott >>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> rspec-users mailing list >>>>>>>>> rspec-users@rubyforge.org >>>>>>>>> http://rubyforge.org/mailman/listinfo/rspec-users >>>>>>>>> >>>>>>>> >>>>>>>> Ok, then would you still insist that: >>>>>>>> >>>>>>>> This: >>>>>>>> >>>>>>>> http://gist.github.com/2372 >>>>>>>> >>>>>>>> Should produce this: >>>>>>>> >>>>>>>> # spec migration_spec.rb >>>>>>>> .F >>>>>>>> >>>>>>>> 1) >>>>>>>> Spec::Mocks::MockExpectationError in 'Migration should find the >>>>>>>> records' >>>>>>>> Mock 'MyModel Class' received unexpected message :count with (no args) >>>>>>>> ./migration.rb:14:in `run' >>>>>>>> ./migration_spec.rb:19: >>>>>>>> >>>>>>>> Finished in 0.009435 seconds >>>>>>>> >>>>>>>> -------------------- >>>>>>>> >>>>>>>> And like I said earlier, this code passes both examples with FlexMock( >>>>>>>> if you simply replace mock with flexmock and uncomment the code in >>>>>>>> spec_helper, of course you need the flexmock gem) >>>>>>> >>>>>>> I can't speak for why it's passing in Flexmock, but I can explain why >>>>>>> it's failing in rspec. >>>>>>> >>>>>>> RSpec clears out all stub methods and message expectations at the end >>>>>>> of each example. In this case, the stub on count is defined in a >>>>>>> before(:all) block, which is only executed once, before all the >>>>>>> examples are run (perhaps before(:any) would be a more clear >>>>>>> expression of this?). After the first example is executed, that stub >>>>>>> goes away. So when the mock receives the :count message in the second >>>>>>> example, it's not expecting it (which is exactly what it's telling >>>>>>> you). If you run the second example by itself (spec migration_spec.rb >>>>>>> -e "should find the records") it will pass. >>>>>>> >>>>>>> You can solve the immediate problem by removing the stubs from the >>>>>>> initial declaration of the MyModel constant and moving them to a >>>>>>> before(:each) block so they get set before each example. >>>>>>> >>>>>>> Another option is to set :null_object => true. That will tell the mock >>>>>>> to ignore unexpected messages, however the stub on find might still >>>>>>> need to move to before(:each) because it returns something. >>>>>>> >>>>>>> Also - this code creates instance variables that get used across >>>>>>> examples. If something happens in the first example to change the >>>>>>> state of @record, you're going to get the same object in the second >>>>>>> example and it becomes a challenge to understand what's happening when >>>>>>> there are failures in the second example. >>>>>>> >>>>>>> I don't use before(:all) blocks this way for exactly this reason. They >>>>>>> are run only once, and can cause a lot of confusion because they leak >>>>>>> state across examples. The way I usually go about something like this >>>>>>> is to create a simple empty class: >>>>>>> >>>>>>> class MyModel; end >>>>>>> >>>>>>> And then set expectations on it before(:each) example. >>>>>>> >>>>>>> You can get the gist of what I'm talking about here: >>>>>>> http://gist.github.com/2438 - I've got two different approaches in two >>>>>>> separate commits, so grab the repo to see both >>>>>> >>>>>> Or you *could* just look at them on line! >>>>>> >>>>>> https://gist.github.com/2438/040f26916032ad864ba51d0d733e16056c77be42 >>>>>> https://gist.github.com/2438/0ee4fcaebbafdbdab77dffd5228a9aae92f17191 >>>>>> >>>>>> >>>>>> >>>>>>> (this is my first time >>>>>>> checking out gist - wow!). >>>>>>> >>>>>>> HTH, >>>>>>> David >>>> >>>> On Fri, Jul 25, 2008 at 8:30 AM, Matt Lins <[EMAIL PROTECTED]> wrote: >>>>> Yes, gist is great! >>>>> >>>>> Thank you very much for taking the time to look at this. I like your >>>>> suggestions very much and will use them. At this point I'm just >>>>> messing around, but I don't understand why this doesn't work. >>>>> >>>>> One more bad implementation if you have time: >>>> >>>> I don't really have much - packing for a week's holiday. >>> >>> Ok, thanks anyway. Enjoy your holiday. :) >>> >>>> >>>>> http://gist.github.com/2372 >>>>> >>>>> I'm removing the constant after each spec runs and redefining it >>>>> before each runs. The second spec still doesn't pass though, even >>>>> though the constant is defined before each spec. >>>> >>>> Is is the same failure? >>> >>> Yes. >> >> What about when you run them each individually? >> >> spec migration_spec.rb - e 'should get a count of the records' >> spec migration_spec.rb - e 'should find the records' > > I actually just did that myself and they both pass separately - so > there is some state-leaking problem. I don't really have the time to > investigate this now, but this is beginning to feel a lot like > "doctor, it hurts when I bang my head against the wall like this ...." > >> >> >>> >>>> >>>>> Again, I realize this is horrible, but it should still work, no? >>>> _______________________________________________ >>>> rspec-users mailing list >>>> rspec-users@rubyforge.org >>>> http://rubyforge.org/mailman/listinfo/rspec-users >>>> >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-users@rubyforge.org >>> http://rubyforge.org/mailman/listinfo/rspec-users >>> >> > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users > _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users