[rspec-devel] Partially mocked objects that define == blow up when another mock exists

Pat Maddox pergesu at gmail.com
Mon Oct 1 20:06:22 EDT 2007


On 10/1/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> On 10/1/07, Pat Maddox <pergesu at gmail.com> wrote:
> > One of my coworkers wrote a class that defines == to have simple value
> > object semantics.  One of our specs partially stubs the value object.
> > A change in the last week or so broke it.  Here's the setup:
> >
> > stub("existing mock", :foo => :foo)
> > class ValueObject
> >   attr_reader :val
> >
> >   def initialize(val)
> >     @val = val
> >   end
> >
> >   def ==(other)
> >     @val == other.val
> >   end
> > end
> >
> > @obj = ValueObject.new :bar
> > @obj.stub!(:some_method)  # blows up with undefined method on
> > #<Spec::Mocks::Proxy>
> >
> > Now, this was easily fixed with changing == to
> >
> > def ==(other)
> >   other.responds_to?(:val) && @val == val
> > end
> >
> > which imo is better anyway, at least in this particular case.  His
> > argument was, "but we're never going to pass in an object of a
> > different class" in which case he should probably check the other
> > object's class just to make sure.
> >
> > Anyway, I was interested in why this failed, because the error message
> > wasn't very helpful.
> >
> > The problem is that in Spec::Mocks::Space#add it calls mocks.include?.
> >  Internally, Ruby uses == in include?, which in this case blows up.
> >
> > I've got two ideas on this.  The first is to check for object identity
> > using equal?.  #add becomes:
> >
> > def add(obj)
> >   mocks << obj unless mocks.detect {|m| m.equal? obj}
> > end
> >
> > This way people can write the first version of == with no problems.
> >
> > Another option is to inform them of duck typing, and that they'll want
> > to either use respond_to or check for the object's class.
> >
> > The first way is less intrusive, and I think I would prefer it solely
> > on that merit.  I don't hate the other way though, and that's just as
> > trivial to implement.  Just rescue NoMethodError in #add with a link
> > to some duck typing page.
> >
> > Here's a patch for the .equal? version: http://pastie.caboo.se/102619
> > I opted not to put it in the tracker because I wanted to generate some
> > discussion first.  Plus there are a lot of patches that are just
> > chilling there and I don't know if anyone's looking at them :)
>
> As luck would have it, I just ran into this exact problem. I think
> your solution is sound. Unless anyone else barks "nay", I'd say go
> ahead and submit the patch to the tracker and I'll apply it.
>
> Cheers,
> David
>
> >
> > Pat
> > _______________________________________________
> > rspec-devel mailing list
> > rspec-devel at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-devel
> >
> _______________________________________________
> rspec-devel mailing list
> rspec-devel at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-devel
>

Ticket is http://rubyforge.org/tracker/?func=detail&atid=3151&aid=14362&group_id=797


More information about the rspec-devel mailing list