【问题标题】: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)
        

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

        【讨论】:

          【解决方案4】:

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

          检查一下:

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

          【讨论】:

            猜你喜欢
            • 2010-10-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-14
            • 2023-01-11
            • 1970-01-01
            相关资源
            最近更新 更多