[rspec-users] Example for attr_accessible?

Pat Maddox pergesu at gmail.com
Tue Oct 16 23:52:53 EDT 2007


On 10/16/07, Steve <vertebrate at gmail.com> wrote:
> On Tue, 16 Oct 2007 13:43:43 -0500, David Chelimsky wrote:
>
> > On 10/16/07, Pat Maddox <pergesu at gmail.com> wrote:
> >> describe Chicken do
> >>   it "should make only :name and :age attr_accessible" do
> >>     Chicken.should_receive(:attr_accessible).with(:name, :age)
> >>     load "#{RAILS_ROOT}/app/models/chicken.rb"
> >>   end
> >> end
> >>
> >> I first saw this technique described by David Chelimsky at
> >> http://rubyforge.org/pipermail/rspec-users/2007-September/002965.html
> >
> > Which I first saw described by Jay Fields at
> > http://blog.jayfields.com/2006/12/rails-unit-testing-activerecord.html
>
> I've been thinking about this throughout the day, and is this a pattern
> that should maybe be implemented in a more widespread pattern? For
> example, check that the model makes the requisite calls to the various
> validation functions? It would seem that unless you have some very custom
> validation methods, that you would be testing rails implementation of its
> validators, by running through all of the various checks manually.
>
> I guess maybe it depends on if you view the testing as mostly testing a
> black box, or if you assume some knowledge of the code internals? Thoughts?

Well, you'll find differing opinions on this.  Every time I've done
validations I've written a spec that actually exercises the behavior.
For example

class Person < ActiveRecord::Base
  validates_presence_of :name
end

describe Person do
  it "should not be valid without a name" do
    p = Person.new
    p.should_not be_valid
    p.errors.on(:name).should == "can't be blank"
  end
end

As far as I'm concerned, that's specifying the behavior.  A person
without a name is not valid, and it results in an error message on
name.  Doing it the way we've discussed in this thread is ugly and
stupid, imo.

However, I had never used attr_accessible up to this point, and in
this case I thought it made sense.  It's just a lot easier to expect
the call itself than to try to test every single column that's not
accessible.  You end up looping through the columns, writing helper
methods to provide default values...it all gets ugly.  So, I thought
this works.

An interesting thing is that since I decided it's okay for
attr_accessible, I'm starting to consider whether it may be okay for
other validations.  afaik David C doesn't have a firm opinion on this,
and I have to admit that mine is softening up a bit.

Personally, if I wanted to extract this pattern, I would use a custom
expectation matcher.

Person.should require_field(:name) =>
  p = Person.new
  p.should_not be_valid
  p.errors.on(:name).should == "can't be blank"

or to make it mirror AR a bit more
Person.should validate_presence_of(:name)

I would be happy with a nice little library of expectation matchers
that handle all the validations like that.  It may seem silly since
the name is essentially the same as the method call itself, but I
prefer it because you're using the object's actual behavior.
Generally I want to exercise the behavior as much as possible and mock
out as little as I can.  The exceptions are when I haven't implemented
an interaction yet, so I mock it out, or when I'm dealing with code
from a lower layer in which case I keep the mocks for speed/dependency
purposes.

Pat


More information about the rspec-users mailing list