[rspec-devel] Fwd: [ rspec-Bugs-6905 ] Mocking rails associations where the association is validated

David Chelimsky dchelimsky at gmail.com
Mon Nov 27 17:38:35 EST 2006


On 11/27/06, aslak hellesoy <aslak.hellesoy at gmail.com> wrote:
> On 11/27/06, Pat Maddox <pergesu at gmail.com> wrote:
> > On 11/27/06, David Chelimsky <dchelimsky at gmail.com> wrote:
> > > On 11/27/06, Pat Maddox <pergesu at gmail.com> wrote:
> > > > Another question :)
> > > >
> > > > When I first wrote the add_person method, my spec looked like this:
> > > >
> > > >   specify "should accept a new person" do
> > > >     @user.people.size.should_be 0
> > > >     @user.add_person Person.new
> > > >     @user.people.size.should_be 1
> > > >   end
> > > >
> > > > That works, of course, and lets me infer that I have the new user.
> > > > However I think it's ugly that I'm accessing people to verify
> > > > something about the user...
> > > >
> > > > So then I decided to change it to this:
> > > >
> > > >   specify "should accept a new person" do
> > > >     mock_person = mock("person")
> > > >     mock_people = mock("people")
> > > >     @user.should_receive(:people).and_return(mock_people)
> > > >     mock_people.should_receive(:<<).with(mock_person)
> > > >     @user.add_person mock_person
> > > >   end
> > > >
> > > > That feels like the more RSpecy way to do this, despite being longer.
> > > > In both cases they dig into people (either checking the size or
> > > > checking that it calls <<), but in the latter case it verifies
> > > > behavior, rather than inferring it from state.  Does that sound right?
> > >
> > > This one is tricky. There are multiple perspectives on how much
> > > mocking you should do in model specs. One view is that model specs are
> > > really small integration specs (model class + database). Another view
> > > is that you should do what you did above, mocking out the other
> > > players where possible.
> > >
> > > I'm leaning towards the first view - that model specs are like little
> > > integration specs. My thinking is that because the way AR is designed,
> > > the things you end up mocking are often internal to AR, which is a
> > > huge mocking no-no (mock YOUR code, not other people's).
> >
> > Weren't we mocking other people's code in the controller specs as well?
> > ARClass.should_receive(:find).with(1).and_return(some_mock_object)
> > ARClass.should_receive(:new).with(:name => "name").and_return(other_mock_object)
> >
> > I'm not really sure what the difference is between mocking that out
> > and mocking players.  At first I thought that it's because the find
> > and new calls appear in my code, but so does players <<.
> >
> >
> > > In this case you could use this to make it feel more RSpecy without
> > > mocking anything:
> > >
> > > specify "should accept a new person" do
> > >   lambda do
> > >     @user.add_person
> > >   end.should_change(@user.people.size).by(1)
> > > end
> > >
> > > I'm not a huge fan of going after @user.people.size here, but I think
> > > that @user.number_of_people might be overkill.
> >
> > After thinking about this some more, I think I like the other version
> > with lots of mocks.  To me, it boils down to what I think is a
> > revelation I had last night...using the specs do define behavior,
> > rather than infer it from state.
> >
> > The one problem I see with my example was what if the User object
> > doesn't define a players method?  Then the spec passes fine, but the
> > code blows up of course.  This would be easily solved if you ensure
> > that partial mocks can only mock methods that the object already has.
> >
> > for example, I've got a user object that has players in this case...when I do
> > user.should_receive(:players)
> > then I think the should_receive call out to call
> > user.respond_to?(players) before mocking the method.  That seems
> > reasonable to me for partial mocks - we're just substituting in some
> > code for behavior that should already exist, because the existing code
> > is too complex or expensive and doesn't need to be executed at the
> > moment.  At the very least, perhaps it could generate a warning such
> > as "WARNING - 'people' not defined on user object."  WDYT?
> >
>
> That would be possible to bake into RSpec, but it would violate one of
> the main principles of BDD. BDD is (among other things) a technique to
> *discover* the interfaces of neighbouring objects N while speccing a
> class C. And while you're speccing C, N might not even exist.
>
> The WARNING idea is interesting though.
>
> > 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
>


More information about the rspec-devel mailing list