Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/1e6a202d041ede30e1650f93d8cb3b16 to your computer and use it in GitHub Desktop.
Save JoshCheek/1e6a202d041ede30e1650f93d8cb3b16 to your computer and use it in GitHub Desktop.
assert_db_query_count test helper for ActiveRecord
require 'active_record'
ActiveRecord::VERSION::STRING # => "5.1.6"
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Schema.define do
self.verbose = false
create_table(:users) do |t|
t.string :name
t.boolean :activated, default: false
end
end
class User < ActiveRecord::Base
# Both of these update the records correctly, but the update_all does it in one query
# and the each { |u| u.update ... } does it in 7 queries! (swap the bool to see what the failure looks like)
if true
def self.activate
update_all activated: true
end
else
def self.activate
all.each { |u| u.update activated: true }
end
end
end
require 'rspec/autorun'
RSpec.describe 'User.activate' do
def assert_db_query_count(expected, &block)
queries = []
record = proc { |*, query| queries << query }
result = ActiveSupport::Notifications.subscribed record, "sql.active_record", &block
expect(queries.size).to(
eq(expected),
"Expected #{expected} quer#{expected == 1 ? 'y' : 'ies'}, got #{queries.size}:\n" \
<< queries.map(&:inspect).join("\n")
)
result
end
it 'updates efficiently updates activated to true' do
%w[yes no yes].map { |n| User.create! name: n }
assert_db_query_count(1) { User.where(name: 'yes').activate }
expect(User.order(:id).pluck(:name, :activated)).to eq [
['yes', true],
['no', false],
['yes', true],
]
end
end
# >> .
# >>
# >> Finished in 0.01921 seconds (files took 0.27017 seconds to load)
# >> 1 example, 0 failures
# >>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment