Question

I've been trying to solve a problem for a few weeks now. I am running rspec tests for my Rails app, and they are working fine except for one error that I can't seem get my head around.

  • I am using MySQL with the InnoDB engine.
  • I have set config.use_transactional_fixtures = true in spec_helper.rb
  • I load my test fixtures manually with the command rake spec:db:fixtures:load.
  • The rspec test is being written for a BackgrounDRb worker, and it is testing that a record can have its state updated (through the state_machine gem).

Here is my problem:

I have a model called Listings. The rspec test calls the update_sold_items method within a file called listing_worker.rb. This method calls listing.sell for a particular record, which sets the listing record's 'state' column to 'sold'. So far, this is all working fine, but when the update_sold_items method finishes, my rspec test fails here:

listing = Listing.find_by_listing_id(listing_id)
listing.state.should == "sold"

expected: "sold",
     got: "current" (using ==)

I've been trying to track down why the state change is not persisting, but am pretty much lost. Here is the result of some debugging code that I placed in the update_sold_items method during the test:

pp listing.state  # => "current"

listing.sell!
listing.save!

pp listing.state  # => "sold"

listing.reload

pp listing.state  # => "current"

I cannot understand why it saves perfectly fine, but then reverts back to the original record whenever I call reload, or Listing.find etc.

Thanks for reading this, and please ask any questions if I haven't given enough information.

Thanks for your help, Nathan B

P.S. I don't have a problem creating new records for other classes, and testing those records. It only seems to be a problem when I am updating records that already exist in the database.

Was it helpful?

Solution

I suspect, like nathan, transaction issues. Try putting a Listing.connection.execute("COMMIT") right before your first save call to break the transaction and see what changes. That will break you out of the transaction so any additional rollback calls will be non-effectual.

Additionally, by running a "COMMIT" command, you could pause the test with a debugger and inspect the database from another client to see what's going on.

The other hypothesis, if the transaction experimentation doesn't yield any results, is that perhaps your model really isn't saving to the database. Check your query logs. (Specifically find the update query).

These kind of issues really stink! Good luck!

OTHER TIPS

If you want to investigate what you have in DB while running tests you might find this helpful...

I have a rspec test where I save @user.save and it works like a charm, but then I wanted to see if it's really saved in the DB.

I opened rails console for test environment

rails c test

ran

User.all

and as expected got nothing

I ran my spec that contains:

user_attr_hash    = FactoryGirl.attributes_for(:user)
@user = User.new user_attr_hash
@user.save
binding.pry

I thought that stopping the test after save would mean that it's persisted, but that's not the case. It seems that COMMIT on the connection is fired later (I have no idea when:\ ) So, as @Tim Harper suggests, you have to fire that commit yourself in the pry console:

pry(#<RSpec::Core::ExampleGroup::Nested_1>)> User.connection.execute("COMMIT")

Now, if you run User.all in your rails console you should see it ;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow