.as_null_object on a double causes Rspec to just hang?

636 views Asked by At

I'm not quite sure how to explain this.

I have an existing Rails 3.1.3 app running RSpec 2.8.1, with a test suite of 284 tests. They will execute over and over again quite happily.

I added a new test today, for a user updating their settings -

require 'spec_helper'

describe UserSettingsController do

  describe 'PUT "update"' do

    let!(:user) { Fabricate :user }

    it 'updates the User with the correct attributes' do
      proxy = double('proxy')   #.as_null_object
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      login_user(user)
      put :update, :user => attributes
    end

  end

end

Initially this test fails because I have a before_filter in my application_controller.rb that also references current_user (which causes an unexpected message on the mock), so I thought to make the mock a null object (see commented out area above).

When I do this though... the whole test suite just hangs as if in an infinite loop, after finishing the test (but before moving on to the next one).

Has anyone seen anything like this before? Am I using .as_null_object incorrectly?

edit: to clarify a few things, login_user is a helper provided by Sorcery for authenticating in tests, and the :user_settings fabricator is just fabricating a hash with a timezone in it.

1

There are 1 answers

1
troutwine On

Unless you :user_settings factory is self-referential, I'd have a look at doing two things. First:

describe UserSettingsController do

  describe 'PUT "update"' do
    let(:proxy) { double('proxy').as_null_object }
    let(:user) { Fabricate :user }

    before(:each) do
      login_user(user)
    end

    it 'updates the User with the correct attributes' do
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      put :update, :user => attributes
    end

  end

end

If this fails as before you know that the problem is somewhere inside of sorcery. (You'll never see the example summary-string output in your console.) Note that I've kept the #as_null_object call: sorcery will be prodding the mocked user for information, mostly filling up hashes. Begin reading here if you're interested. If that doesn't help pinpoint the problem, consider removing login_user altogether. Like so:

describe UserSettingsController do

  describe 'PUT "update"' do
    let(:proxy) { double('proxy') }
    let(:user) { Fabricate :user }

    it 'updates the User with the correct attributes' do
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      put :update, :user => attributes
    end

  end

end

You're stubbing current_user out to be defined by the controller which I think will mean you squeak past your before_filter auth hook, defining current_user as proxy. If there's something goofy going on in all the invocations you've at least cut down a number of them.

I'm still guessing--I didn't build an example app. Good luck.