Reputation: 41
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
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
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