计算执行的查询数量
我想测试某段代码是否执行尽可能少的 SQL 查询。
ActiveRecord::TestCase
似乎有自己的 assert_queries
方法,它就能做到这一点。但由于我没有修补 ActiveRecord,所以它对我来说没什么用处。
RSpec 或 ActiveRecord 是否提供任何官方、公开的方法来计算代码块中执行的 SQL 查询的数量?
I'd like to test that a certain piece of code performs as few SQL queries as possible.
ActiveRecord::TestCase
seems to have its own assert_queries
method, which will do just that. But since I'm not patching ActiveRecord, it's of little use to me.
Does RSpec or ActiveRecord provide any official, public means of counting the number of SQL queries performed in a block of code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我认为您通过提到
assert_queries
回答了自己的问题,但这里是:我建议您查看
assert_queries
背后的代码,并使用它来构建您自己的方法可以用来统计查询。这里涉及的主要魔力是这一行:今天早上我做了一些修补,撕掉了 ActiveRecord 中执行查询计数的部分,并提出了这个:
您将能够引用 ActiveRecord::Base .count_queries 方法在任何地方。将其传递给运行查询的块,它将返回已执行的查询数:
对我来说返回“1”。要实现此功能:将其放入
lib/active_record/query_counter.rb
的文件中,并在config/application.rb
文件中要求它,如下所示:嘿,快点!
可能需要一点解释。当我们调用这一行时:
我们连接到 Rails 3 的小通知框架。它是 Rails 最新主要版本的一个闪亮的小补充,但没有人真正了解。它允许我们使用
subscribe
方法订阅 Rails 中的事件通知。我们传入要订阅的事件作为第一个参数,然后传入响应call
的任何对象作为第二个参数。在这种情况下,当执行查询时,我们的小查询计数器将尽职地增加 ActiveRecord::QueryCounter.query_count 变量,但仅限于真实查询。
不管怎样,这很有趣。我希望它对你有用。
I think you answered your own question by mentioning
assert_queries
, but here goes:I would recommend taking a look at the code behind
assert_queries
and using that to build your own method which you can use to count queries. The main magic involved here is this line:I had a bit of a tinker this morning and ripped out the parts of ActiveRecord that do the query counting and came up with this:
You will be able to reference the
ActiveRecord::Base.count_queries
method anywhere. Pass it a block wherein your queries are run and it will return the number of queries that have been executed:Returns "1" for me. To make this work: put it in a file at
lib/active_record/query_counter.rb
and require it in yourconfig/application.rb
file like this:Hey presto!
A little bit of explanation probably is required. When we call this line:
We hook into Rails 3's little notifications framework. It's a shiny little addition to the latest major version of Rails that nobody really knows about. It allows us to subscribe to notifications of events within Rails by using the
subscribe
method. We pass in the event we want to subscribe to as the first argument then any object that responds tocall
as the second.In this case when a query is executed our little query counter will dutifully increment the ActiveRecord::QueryCounter.query_count variable, but only for the real queries.
Anyway, this was fun. I hope it comes useful to you.
我对 Ryan 脚本的看法(清理了一下并包装在匹配器中),希望它对某人来说仍然是真实的:
我将其放入spec/support/query_counter.rb
并将其放入spec/support/matchers/exceed_query_limit.rb
用法:
My vision of Ryan's script (cleaned up a bit and wrapped in a matcher), hope it is still actual for someone:
I put this to spec/support/query_counter.rb
and this to spec/support/matchers/exceed_query_limit.rb
Usage:
这是 Ryan 和 Yuriy 解决方案的另一种表述,它只是添加到
test_helper.rb
中的一个函数:用法如下:
Here's another formulation of Ryan's and Yuriy's solution that's just a function you add to your
test_helper.rb
:Usage is just:
(基于 Jaime Cham 的回答)
(based on Jaime Cham's answer)
根据 Jaime 的回答,以下内容支持对当前测试用例中迄今为止的查询数量的断言,并将在失败时记录语句。我认为将这样的 SQL 检查与功能测试结合起来实际上很有用,因为它减少了设置工作。
用法:
请注意,查询断言应该立即发生,以防其他断言本身触发额外的查询。
Based on Jaime's answer, the following supports an assertion for the number of queries so far in the current test case, and will log the statements in case of failure. I think it's useful pragmatically to combine a SQL check like this with a functional test as it reduces the setup effort.
Usage:
Note the query assertion should happen immediately in case the other assertions themselves trigger extra queries.
这是一个可以轻松计算与给定模式匹配的查询的版本。
用法:
Here's a version that makes it easy to count queries matching a given pattern.
Usage:
我最终创建了一个小 gem 来抽象这个问题:sql_spy。
只需将其添加到您的 Gemfile 中:
将代码包装在
SqlSpy.track { ... }
:... 中,并在断言中使用该块的返回值:
I ended up creating a tiny gem to abstract this problem: sql_spy.
Just add it to your Gemfile:
Wrap your code inside
SqlSpy.track { ... }
:...and use the return value of the block in your assertions:
我添加了基于 Yuriy 的解决方案检查每个表的查询的功能
RSpec 匹配器看起来像
用法
I added the ability to check queries per table based on Yuriy's solution
The RSpec matchers look like
Usage