Posted about 7 years ago. Visible to the public.

Why stubbing on associated records does not always work as expected

Be careful when stubbing out attributes on records that are defined by associations. Nothing is as it seems to be.

The associated record has its own universe of things; when delegating calls to it, you ca not stub methods on the associated record and expect them to be around. That is a general issue with this pattern/approach.

What's happening?

Consider these classes:

Copy
class Post < ActiveRecord::Base belongs_to :thread def thread_title thread.title end end class Thread < ActiveRecord::Base has_many :posts end

Now look at this spec:

Copy
thread = Thread.make post = Post.make :thread => thread thread.stub :title => 'Hello Universe' post.thread_title.should == 'Hello Universe'

Unfortunately, this spec will fail as post.thread_title is nil.

Why? Because post.thread is not actually a Thread even though looking at its class makes you believe so:

Copy
post.thread.class => Thread

Its real class is ActiveRecord::Associations::BelongsToAssociation which is sometimes exposed, for example when calling undefined methods:

Copy
post.thread.foobar NoMethodError Exception: undefined method `foobar' for #<ActiveRecord::Associations::BelongsToAssociation:0xc7d99a0>

This means that you actually stubbed on the BelongsToAssociation object – those stubs will be gone when our post accesses its thread.\
That also applies when you stub on post.thread instead of thread in the spec; they both have the same object_id.

When debugging, you will also see that post.thread.title is in fact "Hello Universe" while post.thread_title is nil.

How to fix it

Both these approaches work and you are probably doing one of them for most of your specs anyway:

  1. Stub the method that uses the associated record.
  2. Stub the association explicitly:

    Copy
    post.stub :thread => thread

    You need to do this even though (or rather: because of) the belongs_to association that is already in place.

By refactoring problematic code and creating automated tests, makandra can vastly improve the maintainability of your Rails application.

Owner of this card:

Avatar
Arne Hartherz
Last edit:
over 6 years ago
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more