Specs for attributes with default values on the SQL layer


#1

Hi

I’m not sure what would be best practise to treat this case.

Migration:
t.boolean :fetched, :null => false, :default => false

Model:
validates_inclusion_of :fetched, :in => [true, false]

Spec:
it do
article = Article.new(valid_attributes.except(:fetched))
article.should have(1).error_on(:fetched)
end

Like this the spec will always fail because although fetched is excepted
from
the hash returned by valid_attributes, it still gets set to false due to
the
default value. Therefore no error and therefore the spec booms.

A solution would be to use this instead:
article = Article.new(valid_attributes.with(:fetched => nil))

But that would block refactoring if many attributes are tested for
errors.
Ideas?


#2

On Thu, Apr 16, 2009 at 10:43 AM, svoop removed_email_address@domain.invalid wrote:

Spec:
it do
article = Article.new(valid_attributes.except(:fetched))
article.should have(1).error_on(:fetched)
end

Like this the spec will always fail because although fetched is excepted from
the hash returned by valid_attributes, it still gets set to false due to the
default value. Therefore no error and therefore the spec booms.

The two examples you gave are very different semantically. The first
follows “no value was provided, so use the default.” The second is
“an invalid value was provided.”

A solution would be to use this instead:
article = Article.new(valid_attributes.with(:fetched => nil))

But that would block refactoring if many attributes are tested for errors.
Ideas?

What do you mean by it blocks refactorings? This isn’t any different
from the first example, with the exception that you provide a value
instead of letting the default kick in…

Pat


#3

What do you mean by it blocks refactorings? This isn’t any different
from the first example, with the exception that you provide a value
instead of letting the default kick in…

article = Article.new
article.fetched # => false (due to default)

article = Article.new(valid_attributes.except(:fetched))
article.fetched # => false (again due to default)
article.should have(1).error_on(:fetched) # => RED LIGHT

This would work:

article = Article.new(:fetched => nil)
article.fetched # => nil (default overridden)
article.should have(1).error_on(:fetched) # => GREEN LIGHT

The problem is that Article.new doesn’t return an object where all
attributes
are nil and therefore the attributes passed must set defaultet
attributes
explicitly to nil for it to override the defaults.

I wonder how other people treat this case.


#4

On Thu, Apr 16, 2009 at 1:15 PM, svoop removed_email_address@domain.invalid wrote:

I wonder how other people treat this case.
Okay I must be dense because I’m not sure what you mean by it gets in
the way of refactoring.

And you’re right about how it behaves…that’s exactly how default
attrs work. If you want to test that your model doesn’t allow invalid
data, you have to explicitly give it invalid data.

Could you rephrase the problem perhaps? Or wait for someone smarter
to come along.

Pat


#5

Pat M. <pat.maddox@…> writes:

Okay I must be dense because I’m not sure what you mean by it gets in
the way of refactoring.

Actually, scratch that, because…

And you’re right about how it behaves…that’s exactly how default
attrs work. If you want to test that your model doesn’t allow invalid
data, you have to explicitly give it invalid data.

Using .with instead of .except does the trick just fine and does just
that, set
the model explicitly to invalid data.

Cheers, -sven


#6

On Sat, Apr 18, 2009 at 3:09 AM, svoop removed_email_address@domain.invalid wrote:

Using .with instead of .except does the trick just fine and does just that, set
the model explicitly to invalid data.

gah, I totally get it now! Wasn’t noticing that in one case you were
passing in a full attributes hash (valid_attributes) and in the second
you were only setting one value. Makes sense to me now. Glad you
figured it out :slight_smile:

Pat


#7

My question is, why bother? Unless I’m missing something, testing for
the existence of an error that your code will never provide sounds
backwards. Instead test that you DON’T get an error when the required
value isn’t explicitly supplied, to confirm that the default works.
(Although, really, the “pure” time to do that would’ve been before
writing the migration, to get the red-to-green verification. That may
be excessively pedantic though.)

On 4/18/09, Pat M. removed_email_address@domain.invalid wrote:


rspec-users mailing list
removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-users


Have Fun,
Steve E. (removed_email_address@domain.invalid)
ESCAPE POD - The Science Fiction Podcast Magazine
http://www.escapepod.org