[rspec-users] have_one and have_present

David Chelimsky dchelimsky at gmail.com
Sat May 5 13:02:43 EDT 2007

On 5/5/07, nicholas a. evans <nick at ekenosen.net> wrote:
> On 5/4/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> > FYI - Jay Fields has a Validatable framework that includes some
> > test/unit assertions that look like this:
> >
> > Foo.must_validate do
> >   presence_of :name
> >   format_of(:name).with(/^[A-Z]/)
> >   numericality_of(:age).only_integer(true)
> > end
> ...
> > Whether you choose to use his framework or write your own, I think
> > there is something to be learned from its expressiveness.
> Something doesn't sit right with me for both Jay Field's test
> validations and also
> http://spicycode.com/2007/4/2/rspec-expecation-matchers-part-ii
> To me, it feels like both of them are testing the implementation too
> closely, rather than checking the expected behavior.  I think that
> this problem is best exhibited by format_of.  What am I verifying?
> That the production code contains the exact same regex as my spec
> code?  That seems a bit silly to me, when the regex itself is the item
> that should be tested most!  It's what is carrying the behavior.  And,
> while the simple "first character should be a capital letter" may seem
> like a silly one to worry about, what about a more complicated regex,
> such as an email address validation?  I would seriously distrust any
> spec containing a complicated regex which is attempting to validate
> another complicated regex.
> What I'd *really* like is something a lot simpler (even if more
> verbose), that focuses entirely on examples and the behavior exhibited
> for those examples.  Basically, I want to give a set of invalid
> examples, and verify that they are indeed invalid, as well as some
> valid examples, and verify that they pass validation.
> But I'm still having a hard time coming up with a nice syntax for
> this.  I was having a discussion with a coworker about this earlier in
> the week, and I pastied my first thoughts about this here:
> http://pastie.caboo.se/58438  After resting on it a bit, I also came
> up with another syntax, pastied here: http://pastie.caboo.se/59162
> I'll readily admit that Jay Field's DSL looks much nicer than what
> I've come up with so far... but I'd rather stick with the plain
> vanilla rspec, and be certain that I'm asserting an expected model
> behavior against examples than expect the implementation details of
> which ActiveRecord validation was used.
> Am I just making things harder for myself?  Am I missing the boat on a
> useful simplification?

This is a very gray area. I can see arguments for Jay's approach and
for the approach you're going for as well. The trick is to not get up
in the dogma of any given approach and understand why it might or
might not be valuable, and in what situations. Why do we care about
avoiding implementation details in tests? Because they make tests
brittle. Why? Because implementations tend to change more than
interfaces. What about our model implementation might change? Are we
going to possibly change from ActiveRecord::Base to some other
persistence framework?

Assuming very low likelihood that we'll decouple our Rails apps from
AR, then I think it's OK to do these simpler but more implementation
focused tests. They cover a LOT of ground in a very clear way.

Here's another way to look at it. There is a rule of thumb in TDD that
says "test YOUR code, not somebody else's." The idea is that when
you're using someone else's API, you should hide it behind an adapter
that is catered to the needs of your application. In tests of your
code, you specify that they should use the wrapper correctly using
mock implementations of the wrapper. Then you have a small suite of
tests that verifies that your wrapper interacts correctly w/ the 3rd
partly API. This allows you great flexibility in switching to a
different API.

In that case, nobody would blink an eye if you used the mocks to
specify that your model interacts correctly with the adapter.

Accepting that approach, then what is the difference, really, between
that and Jay's approach, which essentially mocks AR and lets you
specify that your model class interacts with it correctly?

More information about the rspec-users mailing list