Tobias
Tobias

Reputation: 41

config.cache_classes = false messing up rspec tests?

I'm following the Ruby on Rails Tutorial by Michael Hartl (railstutorial.org).

At some point I got tired of tests failing just bescause the tests used old cached versions of classes, so I turned off config.cache_classes in the test environment. That fixed the issue and everything went good for some time.

Until I tried implementing the Integration tests in Chapter 8.4.3. At this point the data entered into the database with

it "should make a new user" do
    lambda do
      visit signup_path
      fill_in "Name",         :with => "Example User"
      fill_in "Email",        :with => "[email protected]"
      fill_in "Password",     :with => "foobar"
      fill_in "Confirmation", :with => "foobar"
      click_button
      response.should have_selector("div.flash.success",
                                    :content => "Welcome")
      response.should render_template('users/show')
    end.should change(User, :count).by(1)
  end

would remain in the Database after each test, so only the first time this test ran it would work, after that it always fails until i manually empty the database. Apart from that it worked. But now in chapter 9, again the integration test fails:

describe "when signed in" do

before(:each) do
  @user = Factory(:user)
  visit signin_path
  fill_in :email,    :with => @user.email
  fill_in :password, :with => @user.password
  click_button
end

it "should have a signout link" do
  visit root_path
  response.should have_selector("a", :href => signout_path,
                                     :content => "Sign out")
end

This time it just doesn't work, the user is not getting logged in and the resulting page has no sign out link, just the normal sign in link. When testing this in a webbrowser it works fine.

It took me hours and days of searching the internet and testing different stuff and finally I found the solution: Turning config.cache_classes back on. Now it works flawlessly.

So can anyone explain to me why config.cache_classes makes the tests fail? And how can I turn off caching without messing up my tests?

Thanks in Advance,

Best regards, Tobias

Upvotes: 4

Views: 3604

Answers (2)

Jacob
Jacob

Reputation: 345

When you make a Capybara call, it uses rack-test to emulate a call to the rails app. Every time a call is completed, it reloads all rails classes. What this means is that the @user object you created before you called 'visit signin_path' gets nil'd out because all ActiveRecord objects have been reloaded.

When you set cache-classes to true, it tells Rack not to reload the ActiveRecord objects on every request, so your tests pass again.

I believe that if you want the test you wrote above to pass without turning on cache-classes, you should move the '@user = Factory(:user)' line below the 'visit signin_path' line.

Upvotes: 2

markstewie
markstewie

Reputation: 9587

I had exactly the same problem and like you setting config.cache_classes to true solved the problem. But caching classes in the test environment really isn't what you want I don't think. I certainly don't understand why caching classes makes the tests pass.

So the way I found to solve this was to install a database cleane as the reason the tests are failing is due to duplicate entries in the test database. https://github.com/bmabey/database_cleaner

Then in your gemfile, in your test group add this.

gem 'database_cleaner', '0.6.6'

then run "bundle install" to install this gem

Then... in your spec_helper.rb file, add this..

RSpec.configure do |config|
.
.
.
.
   config.before(:each) do
      DatabaseCleaner.strategy = :truncation
      DatabaseCleaner.clean
   end

This will clear your test database before each run of your rspec tests.

Hope this helps. Cheers, mark.

Upvotes: 1

Related Questions