Testing After_Commit with Rspec and Mocking

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



Leave a reply



Submit