我正在rails中创建REST API。我正在使用RSpec。我想最小化数据库调用的数量,所以我想添加一个自动测试,验证作为特定操作的一部分执行的数据库调用的数量。 有没有一种简单的方法将其添加到我的测试中? 我正在寻找的是监视/记录由于单个API调用而对数据库进行的调用的一些方法。 如果使用RSpec无法做到这一点,但可以使用其他一些测试工具来完成,那也很棒。
答案 0 :(得分: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)
您可能希望过滤掉一些语句,例如启动/提交事务或发出活动记录以确定表的结构。
答案 1 :(得分:1)
您可能有兴趣使用 explain 。但这不会是自动的。您需要手动分析每个操作。但也许这是一件好事,因为重要的不是db调用的数量,而是它们的性质。例如:他们使用索引吗?
检查一下:
http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/
答案 2 :(得分:0)
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 :(得分:0)
使用db-query-matchers宝石。
expect { subject.make_one_query }.to make_database_queries(count: 1)