Spec'ing validates_uniqueness_of :whatever

Hello

I am learning rspec and trying to especify the activerecord validations
of my models.

How would I make a require_uniqueness_of specification for a field.
Can I make this with mocks, without touching the database?
Can somebody point me to some information or plugin for this issue.

Thank you very much.

Juan M. Cervera

IMO this function should be tested using the database, since it relies
heavily on the data.


Courtenay
@(o…O)@

On Wed, Apr 2, 2008 at 1:19 AM, Courtenay [email protected] wrote:

IMO this function should be tested using the database, since it relies
heavily on the data.

Agreed. Create a record, then create another record with duplicate
data, and verify that the second record is invalid.

Pat

Hi Juanma,

I do this this way:

describe Model do
def create(options={})
Model.create(options)
end

it “should not allow duplicate names” do
model = create(:name => “name”)
new_model = create(:name => “name”)

 new_model.should have_error_on(:name, :taken)

end
end


Matt Berther

Thanks to all for your answers.
I also have found a plugin with matchers for active record validations,
associations and even useful matchers for views.

It has a matcher for validates_uniqueness_of that doesn’t got to the
database.

The url is Google Code Archive - Long-term storage for Google Code Project Hosting.

¿What do you think of using this plugin?

Juanma C…

The test asserts that you call validates_uniqueness_of, but it doesn’t
actually test your logic.
So it’s useful to see if someone accidentally deletes your code, but
if you have

validates_uniqueness_of :user, :scope => :project_id

or something more complex, it won’t test this behavior.

One of the rules that I learned with TDD, that I brought with me to
BDD, is that you only specify or test what you write. Everything else
is assumed to behave as intended. This rule is, among other things,
intended to keep us productive: we can’t write a test suite for an
entire framework every time we use that framework to implement an
application. At some point, we have to trust that the frameworky bits
work as intended.

I don’t exactly assume that the code I’m depending on is well tested,
just that it’s not my job to specify its behaviour.

If you were to write an example that creates two models, and ensures
that the duplicate errored appropriately, my “rule” is violated. Each
of your examples is then specifying the behaviour of the
validates_uniqueness_of method, which you didn’t write.

Doing this with mocks ensures that you called validates_uniqueness_of,
and doesn’t test the behaviour of the method which, since you didn’t
write it, get to assume behaves as expected. This is where my “rule”
falls down: mocking the call prevents you from changing the
implementation without changing the behaviour.

That is to say that you may want to, in the future, roll your own
uniqueness validation that is called in a different way than
ActiveRecord’s, but behaves in the same way. If you mocked, you could
change the implementation without changing the behaviour, and still
have a failing example.

This is where the line is drawn for me: I need to be able to change
the implementation, and only have my examples fail when I’ve changed
the behaviour.

So, in this case, using mocks and expecting Rails’ built-in validation
is fragile. But in general, I try to stick to the “rule” (let’s say
guideline from now on) that I outlined above.

-Steven

On Thu, Apr 3, 2008 at 10:41 PM, Steven B. [email protected]
wrote:

If you were to write an example that creates two models, and ensures
that the duplicate errored appropriately, my “rule” is violated. Each
of your examples is then specifying the behaviour of the
validates_uniqueness_of method, which you didn’t write.

I don’t really agree with this. The desired behavior is to disallow
two records with the same data. v_u_o is simply a quick and easy
means to that end.

Pat

On Thu, Apr 3, 2008 at 4:38 AM, Juanma C. [email protected]
wrote:

Thanks to all for your answers.
I also have found a plugin with matchers for active record validations,
associations and even useful matchers for views.

It has a matcher for validates_uniqueness_of that doesn’t got to the
database.

The test asserts that you call validates_uniqueness_of, but it doesn’t
actually test your logic.
So it’s useful to see if someone accidentally deletes your code, but if
you have

validates_uniqueness_of :user, :scope => :project_id

or something more complex, it won’t test this behavior.

If you were to write an example that creates two models, and ensures
that the duplicate errored appropriately, my “rule” is violated.
Each
of your examples is then specifying the behaviour of the
validates_uniqueness_of method, which you didn’t write.

I don’t really agree with this. The desired behavior is to disallow
two records with the same data. v_u_o is simply a quick and easy
means to that end.

Right. As I said (or intended to) that particular example was so
simple that it was a grey area. But it did cause me to think about
the problem, and I found it interesting.

-Steven

On Fri, Apr 4, 2008 at 2:12 AM, Steven B. [email protected]
wrote:

Right. As I said (or intended to) that particular example was so
simple that it was a grey area. But it did cause me to think about
the problem, and I found it interesting.

While I certainly subscribe to the “don’t test what you didn’t write”
philosophy for the most part. I do think that there are gray areas.
Quoting S.n from a bit earlier in this thread:

I don’t exactly assume that the code I’m depending on is well tested,
just that it’s not my job to specify its behavior.

One of the gray areas is that despite all good intentions, sometimes
the specification of that behavior isn’t entirely clear, even if that
specification is written down somewhere as specs, or traditional
documentation. Problems can creep in when my understanding doesn’t
exactly match the writer’s intent.

In these cases, it seems to me that writing a spec which proves that
my interpretation of an interface by specifying the results rather
than just the presence of the call, just MIGHT be a reasonable thing
to do, and might protect against the possibility that the writer’s
interpretation changes due either to evolution or a ‘bug-fix.’


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/