3

我正在 Rails 中创建一个 REST API。我正在使用 RSpec。我想尽量减少数据库调用的数量,所以我想添加一个自动测试来验证作为某个操作的一部分执行的数据库调用的数量。有没有一种简单的方法可以将它添加到我的测试中?我正在寻找的是某种方法来监视/记录由于单个 API 调用而对数据库进行的调用。如果这不能用 RSpec 完成,但可以用其他一些测试工具完成,那也很好。

4

4 回答 4

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)

您可能希望过滤掉一些语句,例如启动/提交事务的语句或活动记录发出的语句以确定表的结构。

于 2012-06-29T21:05:54.910 回答
1

您可能对使用explain感兴趣。但这不会是自动的。您将需要手动分析每个操作。但也许这是一件好事,因为重要的不是数据库调用的数量,而是它们的性质。例如:他们是否使用索引?

检查这个:

http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/

于 2012-06-29T20:38:54.640 回答
1

使用db-query-matchers gem。

expect { subject.make_one_query }.to make_database_queries(count: 1)
于 2019-03-21T11:01:00.610 回答
0

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)
于 2014-10-06T23:49:51.667 回答