【问题标题】:How to test the number of database calls in Rails如何在 Rails 中测试数据库调用的次数
【发布时间】:2012-06-28 16:36:52
【问题描述】:
我正在 Rails 中创建一个 REST API。我正在使用 RSpec。我想尽量减少数据库调用的数量,所以我想添加一个自动测试来验证作为某个操作的一部分执行的数据库调用的数量。
有没有一种简单的方法可以将它添加到我的测试中?
我正在寻找的是某种方法来监视/记录由于单个 API 调用而对数据库进行的调用。
如果这不能用 RSpec 完成,但可以用其他一些测试工具完成,那也很好。
【问题讨论】:
标签:
ruby-on-rails
database
performance
unit-testing
rspec
【解决方案1】:
使用db-query-matchers gem。
expect { subject.make_one_query }.to make_database_queries(count: 1)
【解决方案2】:
Fredrick 的回答对我很有帮助,但就我而言,我还想知道每个 ActiveRecord 类的调用次数。我做了一些修改,最后得到了这个,以防它对其他人有用。
class SqlCounter< ActiveSupport::LogSubscriber
# Returns the number of database "Loads" for a given ActiveRecord class.
def self.count(clazz)
name = clazz.name + ' Load'
Thread.current['log'] ||= {}
Thread.current['log'][name] || 0
end
# Returns a list of ActiveRecord classes that were counted.
def self.counted_classes
log = Thread.current['log']
loads = log.keys.select {|key| key =~ /Load$/ }
loads.map { |key| Object.const_get(key.split.first) }
end
def self.reset_count
Thread.current['log'] = {}
end
def sql(event)
name = event.payload[:name]
Thread.current['log'] ||= {}
Thread.current['log'][name] ||= 0
Thread.current['log'][name] += 1
end
end
SqlCounter.attach_to :active_record
expect do
# do stuff
end.to change(SqlCounter, :count).by(2)
【解决方案3】:
Rails 3 中最简单的事情可能是挂钩到通知 API。
此订阅者
class SqlCounter< ActiveSupport::LogSubscriber
def self.count= value
Thread.current['query_count'] = value
end
def self.count
Thread.current['query_count'] || 0
end
def self.reset_count
result, self.count = self.count, 0
result
end
def sql(event)
self.class.count += 1
puts "logged #{event.payload[:sql]}"
end
end
SqlCounter.attach_to :active_record
将每个执行的sql语句打印到控制台并计算它们。然后,您可以编写规范,例如
expect do
# do stuff
end.to change(SqlCounter, :count).by(2)
您可能希望过滤掉一些语句,例如启动/提交事务的语句或活动记录发出的语句以确定表的结构。