# Strange Little Problem

**URL:** <https://www.ruby-forum.com/t/strange-little-problem/115546>\
**Category:** Rails\
**Created:** [September 26, 2007, 4:55am UTC](https://www.ruby-forum.com/t/strange-little-problem/115546 "2007-09-26T04:55:58Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 4:55am UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/1 "2007-09-26T04:55:58Z")

</div>

I just created a simple model and started to write unit tests for it  
(I’ve cleaned out extraneous stuff).

The migration is:

class CreateMembers \< ActiveRecord::Migration  
def self.up  
create\_table :members do |t|  
t.column :name, :string  
t.column :number, :string  
end  
end

def self.down  
drop\_table :members  
end  
end

The model is:

class Member \< ActiveRecord::Base  
validates\_uniqueness\_of :number  
end

The testing fixture is:

numeric\_only\_member:  
id: 1  
name: John S.  
number: 15171914  
alpha\_numeric\_member:  
id: 2  
name: Joanne Jones  
number: wke1234

So if I write a little test case (yes I know hard coded values are  
fragile):

require File.dirname( **FILE** ) + ‘/…/test\_helper’  
require ‘member’

class ExampleTest \< Test::Unit::TestCase  
fixtures :members

def test\_uniqueness\_of\_member  
dup\_member = Member.new(:name =\> ‘duplicate’, :number =\>  
‘15171914’)

```
assert !dup_member.save
assert_equal 1, dup_member.errors.count
assert_equal "has already been taken",

```

dup\_member.errors.on(:number)  
end  
end

Problem:

“assert\_equal 1, dup\_member.errors.count” will fail with:  
test\_uniqueness\_of\_member(SimpleTest) [test/unit/simple\_test.rb:11]:  
\<1\> expected but was \<2\>.

The following line would also fail with:  
test\_uniqueness\_of\_member(SimpleTest) [test/unit/simple\_test.rb:12]:  
\<“has already been taken”\> expected but was  
\<[“has already been taken”, “has already been taken”]\>.

Solution:

If I remove " require ‘member’ " from the test case then everything  
passes. I have no idea why. (Yes I’m a newbie, please don’t laugh and  
point). I’m digging through ActiveRecord, UnitTest, and Ruby docs and  
source but haven’t found an answer yet. Any ideas?

Thanks…qb

---

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 2:53pm UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/2 "2007-09-26T14:53:32Z")

</div>

On Sep 25, 2007, at 10:55 PM, qb wrote:

> ```
> end
> 
> ```
> 
> validates\_uniqueness\_of :number  
> end
> 
> The testing fixture is:
> 
> numeric\_only\_member:  
> id: 1  
> name: John S.  
> number: 15171914

You might need:  
number: “15171914”  
So that YAML keeps this a string and not an integer. You’re not  
using members(:numeric\_only\_member).number so it might not matter  
(the database should be a string regardless).

> alpha\_numeric\_member:  
> id: 2  
> name: Joanne Jones  
> number: wke1234
> 
> So if I write a little test case (yes I know hard coded values are  
> fragile):
> 
> require File.dirname( **FILE** ) + ‘/…/test\_helper’  
> require ‘member’

You shouldn’t need this as Rails will auto-load it when Member is  
first used.

> ```
> assert_equal "has already been taken",
> 
> ```
> 
> The following line would also fail with:
> 
> Thanks…qb

I _think_ that Member has already been defined when your ‘require  
“member”’ is executed and since the idempotency of ‘require’ is based  
on the argument (i.e., require ‘foo’ and require ‘./foo’ will load  
foo.rb from the current directory twice), the explicit require re-  
opens the Member class and hits the validates\_uniqueness\_of a second  
time. In addition to removing your “require ‘member’”, I’d also  
suggest writing your test like this:

class ExampleTest \< Test::Unit::TestCase  
fixtures :members

def test\_uniqueness\_of\_member  
dup\_member = Member.new(:name =\> ‘duplicate’,  
:number =\> members  
(:numeric\_only\_member).number)

```
 assert ! dup_member.valid?
 assert dup_member.errors[:number]
 assert_match /has already been taken/, dup_member.errors.on

```

(:number)  
end  
end

You want to know that the record isn’t valid, there’s no need to  
actually try to save it.  
You should check that the field has an error message, rather than the  
total error count.  
I tend to test for things like error message text with regexps that  
will allow some flexibility in the actual value. (e.g., “has already  
been taken. Please choose another and try again.”)

However, all you’re doing is testing that the validates\_uniqueness\_of  
works. Don’t you think that the Rails team already does that? You  
could make a case for verifying that something like a custom format  
is behaving correctly or that you’re using the :scope option as you  
expect, but unless you’re just practicing and convincing yourself how  
things work, I’d not normally test the things that Rails does.

-Rob

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 8:35pm UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/3 "2007-09-26T20:35:46Z")

</div>

On 9/25/07, qb [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> If I remove " require ‘member’ " from the test case then everything  
> passes. I have no idea why. (Yes I’m a newbie, please don’t laugh and  
> point). I’m digging through ActiveRecord, UnitTest, and Ruby docs and  
> source but haven’t found an answer yet. Any ideas?

As Rob pointed out, it’s being caused by your model file being loaded  
twice, and thus the validates\_uniqueness\_of being run twice. You end  
up getting two (identical) error messages.

The “second” load of your model file is actually coming from the  
“fixtures” line, which ends up calling:

require\_dependency ‘member’

In order for require\_dependency to do it’s magic, it has to turn your  
file name into an absolute path. So you get the effect of:

require ‘member’  
require ‘/some/absolute/path/to/member.rb’

Ruby doesn’t know that these are the same file, so it ends up loading  
the file twice, thus doubling the validates declarations.

So, the short answer is: don’t “require” your models in your test  
cases (or use require\_dependency).

---

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 8:45pm UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/4 "2007-09-26T20:45:42Z")

</div>

On 9/26/07, Rob B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> However, all you’re doing is testing that the validates\_uniqueness\_of  
> works.

Rob, is that _all_ he’s doing? The test is too elaborate, but a case  
could be made that this is a regression test for the business rule  
that “Member numbers must be unique”.

It would protect him from coming along later and inadvertently  
removing that validation rule.

I agree that we shouldn’t be testing Rails itself.

---

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 9:52pm UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/5 "2007-09-26T21:52:32Z")

</div>

On Sep 26, 2007, at 2:44 PM, Bob S. wrote:

> I agree that we shouldn’t be testing Rails itself.

Stu Halloway addressed this at erubycon in Columbus,OH this summer.

Blog: [http://relevancellc.com/2007/7/17/posted-slides-how-not-to-test-](http://relevancellc.com/2007/7/17/posted-slides-how-not-to-test-)  
validations  
Slides: [http://relevancellc.com/assets/2007/7/17/KeepingTestsDry.pdf](http://relevancellc.com/assets/2007/7/17/KeepingTestsDry.pdf)

If you’re interested in a test to alert you when/if a validation is  
removed accidentally, then you should be devising a test for _that_  
(presence) and letting Rails make sure that validates\_\*\_of does the  
right thing.

-Rob

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![qbqbqb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/q/b4bc9f/32.png) [@qbqbqb](https://www.ruby-forum.com/u/qbqbqb)\
**Post date:** [September 26, 2007, 10:20pm UTC](https://www.ruby-forum.com/t/strange-little-problem/115546/6 "2007-09-26T22:20:40Z")

</div>

On 9/26/07, Rob B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > It would protect him from coming along later and inadvertently  
> > If you’re interested in a test to alert you when/if a validation is  
> > removed accidentally, then you should be devising a test for _that_  
> > (presence) and letting Rails make sure that validates\_\*\_of does the  
> > right thing.

Well, that sounds good in theory. But in those slides, slide 18 looks  
great but the stuff on 19/20 is a mess!

Devising a test for the presence of validates\_uniqueness\_of (instead  
of exercising it) is non-trivial. And I’m not sure that’s somehow  
“better” or “DRY’er” than just trying to create a duplicate and seeing  
it fail.

I’m really not trying to test whether I have a validates\_uniqueness\_of  
declaration, and I’m not trying to test whether  
validates\_uniqueness\_of works in the abstract (the test doesn’t prove  
that anyway). Instead, I’m trying to test that my model doesn’t allow  
the number to be duplicated (regardless of the details of the  
implementation).

IMHO, something like slide 17 is the correct approach, and not 18.

Cheers,  
Bob
