Testing after_commit with RSpec and mocking
Try to use test_after_commit gem
or add following code in spec/support/helpers/test_after_commit.rb - Gist
Testing an after_commit hook in Rails 4 with transactional fixtures enabled
I solved this by putting the following code in spec/support/helpers/test_after_commit.rb
require 'active_record/connection_adapters/abstract/transaction'
module ActiveRecord
module ConnectionAdapters
class SavepointTransaction < OpenTransaction
def perform_commit_with_transactional_fixtures
commit_records if number == 1
perform_commit_without_transactional_fixtures
end
alias_method_chain :perform_commit, :transactional_fixtures
end
end
end
https://gist.github.com/cmaitchison/5168104
Skip callbacks on Factory Girl and Rspec
I'm not sure if it is the best solution, but I have successfully achieved this using:
FactoryGirl.define do
factory :user do
first_name "Luiz"
last_name "Branco"
#...
after(:build) { |user| user.class.skip_callback(:create, :after, :run_something) }
factory :user_with_run_something do
after(:create) { |user| user.send(:run_something) }
end
end
end
Running without callback:
FactoryGirl.create(:user)
Running with callback:
FactoryGirl.create(:user_with_run_something)
Rails, using the dirty or changed? flag with after_commit
You can do a few things to check...
First and foremost, you can check an individual attribute as such:
user = User.find(1)
user.name_changed? # => false
user.name = "Bob"
user.name_changed? # => true
But, you can also check which attributes have changed in the entire model:
user = User.find(1)
user.changed # => []
user.name = "Bob"
user.age = 42
user.changed # => ['name', 'age']
There's a few more things you can do too - check out http://api.rubyonrails.org/classes/ActiveModel/Dirty.html for details.
Edit:
But, given that this is happening in an after_commit
callback, the model has already been saved, meaning knowledge of the changes that occurred before the save are lost. You could try using the before_save
callback to pick out the changes yourself, store them somewhere, then access them again when using after_commit
.
Rails 3: ActiveRecord observer: after_commit callback doesn't fire during tests, but after_save does fire
To properly execute database commits you need to enable config.use_transactional_fixtures
, but I'd recommend you consider different strategies as that option is disabled by default for the sake of good test design, to enforce your tests to be as unitary and isolated as possible.
First, you can run ActiveRecord callbacks with #run_callbacks(type)
, in your case model.run_callbacks(:commit)
My preferred strategy is to have a method with the logic you want to run, then declare the hook using the method name, then test the method behavior by calling it directly and test that the method is called when the hook is run.
class Person
after_commit :register_birth
def register_birth
# your code
end
end
describe Person do
describe "registering birth" do
it "registers ..." do
end
it "runs after database insertion" do
expect(model).to receive(:register_birth)
model.run_callbacks(:commit)
end
end
end
That assumes that whatever logic you have on the callback is not essential for the model state, i.e. doesn't change it to something you need to consume right away, and that any other model that interacts with it is indifferent to it. And as such isn't required to run in a test context. That is a powerful design principle that in the long term prevents callbacks to get out of control and generate dependencies for tests by demanding some property unrelated to the unit you are testing to be setup only to be consumed on a callback that you don't care about at that moment.
But, in the end you know your domain and design requirements better than a stranger so, if you really need the after_commit
to run, you can force it with model.run_callbacks(:commit)
. Just encapsulate that on your factory/fixture and you don't have to remember it every time.
Related Topics
How to Extract the Sign of an Integer in Ruby
Heroku App Fails to Start - 'Require': No Such File to Load -- Sinatratestapp (Loaderror)
Set the Display Precision of a Float in Ruby
Generating a Short Uuid String Using Uuidtools in Rails
Scientific Programming with Ruby
How to Append Data to JSON in Ruby/Rails
How to Configure Action Mailer (Should I Register Domain)
Bundle Install' Failed Due to Permission Denied
Rake Db:Migrate Error with MySQL2 Gem - Library Not Loaded: Libssl.1.0.0.Dylib
Why Is Ruby's Date Class Automatically Loaded But Datetime Is Not
How to Convert a Ruby String Range to a Range Object
In Ruby, Should I Use ||= or If Defined? for Memoization
Rspec and Shoulda - Complementary or Alternatives
Converting Nested Hash Keys from Camelcase to Snake_Case in Ruby