Before_validation callbacks bypassed when stubbing :valid?

I’m testing an ActiveRecord model using rspec and mocha, and found that
if I stub out the :valid? method, all before_validation callbacks are
also skipped!

Not ideal - I still want the callbacks to execute, but the validation to
return true.
Anyone know how to achieve this?

class Item < ActiveRecord::Base
before_validation :do_something

def do_something
raise “hell”
end
end

Item.any_instance.stubs(:valid?).returns(true)
item = Item.new
item.valid?

On 15 Apr 2008, at 23:05, Zubin H. wrote:

Item.any_instance.stubs(:valid?).returns(true)
item = Item.new
item.valid?

Any reason why you are not using pure mocks here? I assume it’s not
Item you are testing, but some other model that is associated with it?

Ashley


http://www.patchspace.co.uk/

Ashley M. wrote:

Any reason why you are not using pure mocks here? I assume it’s not
Item you are testing, but some other model that is associated with it?

Hi Ashley, yes, you’re spot on - I’m using other associated models. I
just simplified it for illustration. Here’s what I’m really testing:

order.rb

has_one :freight_selection
def calculate_freight_cost(freight_method)

… (based on order total and freight method)

end

freight_selection.rb

belongs_to :order
belongs_to :freight_method
before_validation :set_freight_price

def set_freight_price
self.price = order.calculate_freight_cost(freight_method)
end

def validate

… (confirms that freight_method is valid for order’s shipping

address)
end

I don’t need to validate the freight selection since that’s handled
elsewhere - I just want it to be valid. But I expected the
before_validation filter to run. I’ve found a workaround, but I guess
I’d like to understand this behaviour more, cause it had me stuck for a
while. Is Mocha causing this or Rails?

On 16 Apr 2008, at 00:01, Zubin H. wrote:

I don’t need to validate the freight selection since that’s handled
elsewhere - I just want it to be valid. But I expected the
before_validation filter to run. I’ve found a workaround, but I guess
I’d like to understand this behaviour more, cause it had me stuck
for a
while. Is Mocha causing this or Rails?

It’s simply because the :valid? method is what triggers the filter,
and you are overriding it. (There’s nothing in the runtime sitting
and watching for you to send the message, it’s handled when it’s
received).

I suggest you take one of two approaches:

  • If you are trying to build a suite of database-backed specs to prove
    the model layer works, then actually create a valid FreightSelection -
    whatever that entails. (Actually, better to use a story here, I think.

  • If you are trying to spec the Order class, then use a pure Mocha
    mock that stubs :id, :valid?, and whatever else ActiveRecord needs to
    keep it happy (look at rails_example_group.rb in the RSpec on Rails
    plugin for inspiration). This way you have full control over the
    second object.

Hope this helps

Ashley


http://www.patchspace.co.uk/

On 16 Apr 2008, at 12:34, Edvard M. wrote:

you could consider implementing
class method new_valid for each of your objects, so that whenever the
concept of a valid object changes, there’s
only one place you have to fix.

Or equally, you could have a Factory class that knows how to create
valid objects. This can be handy for generating test data, and
separates it from the class under test. (Some metaprogramming would
let you define that in one class and still have it available as
MyModel.new_valid.)

Zubin - I am still leaning towards the mock approach though, unless
you don’t have integration tests for your app, in which case having a
model-layer test suite would add value. (But full-stack integration
tests + model unit tests would be better).

Ashley


http://www.patchspace.co.uk/

On Wed, Apr 16, 2008 at 1:05 AM, Zubin H. [email protected]
wrote:

I’m testing an ActiveRecord model using rspec and mocha, and found that
if I stub out the :valid? method, all before_validation callbacks are
also skipped!

Naturally, as it is AR’s valid method which triggers those callbacks,
and you just stubbed it.

Not a straight answer to your question, but hopefully helpful
nevertheless: you could consider implementing
class method new_valid for each of your objects, so that whenever the
concept of a valid object changes, there’s
only one place you have to fix. However, as Ashley suggested, it might
be that you’d rather want to resort to pure
mock objects instead.


“One day, when he was naughty, Mr Bunnsy looked over the hedge into
Farmer Fred’s field and it was full of fresh green lettuces. Mr
Bunnsy, however, was not full of lettuces. This did not seem fair.”
– Terry Pratchett, Mr. Bunnsy Has An Adventure

Ashley, Edvard:

Thank you both for your advice and comments.
For now, I’ve implemented fixture_replacement.
Perhaps a story would be better, but this is working well for now.

Cheers,
Zubin

On Wed, Apr 16, 2008 at 2:54 PM, Ashley M.
[email protected] wrote:

Or equally, you could have a Factory class that knows how to create
valid objects. This can be handy for generating test data, and
separates it from the class under test. (Some metaprogramming would
let you define that in one class and still have it available as
MyModel.new_valid.)

Yep, that’s better. This is very similar to what I just recently did:
I created a factory which creates
pure stub objects for all more complex models I needed in tests.
However, I mostly do just
fine having all the stubs/mocks in the spec file concerned; that’s the
approach I like the most,
as then I have everything I need in a single file.

“One day, when he was naughty, Mr Bunnsy looked over the hedge into
Farmer Fred’s field and it was full of fresh green lettuces. Mr
Bunnsy, however, was not full of lettuces. This did not seem fair.”
– Terry Pratchett, Mr. Bunnsy Has An Adventure

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs