Event 分析器
EventProf 在你的测试套件运行期间收集各种测量指标(比如 ActiveSupport::Notifications)。
它的工作很类似于 rspec --profile 但可追踪任意事件。
输出范例:
[TEST PROF INFO] EventProf results for sql.active_record
Total time: 00:00.256 of 00:00.512 (50.00%)
Total events: 1031
Top 5 slowest suites (by time):
AnswersController (./spec/controllers/answers_controller_spec.rb:3) – 00:00.119 (549 / 20) of 00:00.200 (59.50%)
QuestionsController (./spec/controllers/questions_controller_spec.rb:3) – 00:00.105 (360 / 18) of 00:00.125 (84.00%)
CommentsController (./spec/controllers/comments_controller_spec.rb:3) – 00:00.032 (122 / 4) of 00:00.064 (50.00%)
Top 5 slowest tests (by time):
destroys question (./spec/controllers/questions_controller_spec.rb:38) – 00:00.022 (29) of 00:00.064 (34.38%)
change comments count (./spec/controllers/comments_controller_spec.rb:7) – 00:00.011 (34) of 00:00.022 (50.00%)
change Votes count (./spec/shared_examples/controllers/voted_examples.rb:23) – 00:00.008 (25) of 00:00.022 (36.36%)
change Votes count (./spec/shared_examples/controllers/voted_examples.rb:23) – 00:00.008 (32) of 00:00.035 (22.86%)
fails (./spec/shared_examples/controllers/invalid_examples.rb:3) – 00:00.007 (34) of 00:00.014 (50.00%)教学
目前,EventProf 仅支持 ActiveSupport::Notifications。
激活 EventProf:
RSpec
使用 EVENT_PROF 环境变量设置为事件名称:
# Collect SQL queries stats for every suite and example
EVENT_PROF='sql.active_record' rspec ...你可以同时追踪多个事件:
EVENT_PROF='sql.active_record,perform.active_job' rspec ...Minitest
使用 EVENT_PROF 环境变量设置为事件名称:
# Collect SQL queries stats for every suite and example
EVENT_PROF='sql.active_record' rake test或者也可以使用 CLI 选项:
# Run a specific file using CLI option
ruby test/my_super_test.rb --event-prof=sql.active_record
# Show the list of possible options:
ruby test/my_super_test.rb --help与 Minitest::Reporters 一起使用
如果在你的项目中使用了 Minitest::Reporters,那么你必须明确在测试帮助方法文件中声明它:
require 'minitest/reporters'
Minitest::Reporters.use! [YOUR_FAVORITE_REPORTERS]注意
当你以 gem 安装了 minitest-reporters 但并未在你的 Gemfile 里声明时, 确保总是在测试运行命令之前使用 bundle exec (但我们相信你总会这样做的)。 否则,你会得到由 Minitest plugin 系统造成的报错, 该系统对所有的 minitest/*_plugin.rb 扫描 $LOAD_PATH 内的入口, 因此该场景中可用的 minitest-reporters plugin 的初始化就不正确了。
如果你在用 Rails,参看 Rails guides来了解所有可用的事件。
如果你在用 rom-rb,那么可能会对分析'sql.rom' 事件感兴趣。
配置
默认情况下,EventProf 仅收集关于 top-level 组的信息(aka suites), 但你也可以分析单独的用例。只用设置好配置选项:
TestProf::EventProf.configure do |config|
config.per_example = true
end或者提供 EVENT_PROF_EXAMPLES=1 环境变量。
另一个有用但配置参数是——rank_by。它负责对统计数字排序——或者是事件耗费时间或者是出现次数:
EVENT_PROF_RANK=count EVENT_PROF='instantiation.active_record' be rspec参看 event_prof.rb 了解所有可用配置选项及其用法。
与 RSpecStamp 一起使用
EventProf 可跟 RSpec Stamp 一起使用来以自定义 tag 自动标识_慢_测试用例,比如:
EVENT_PROF="sql.active_record" EVENT_PROF_STAMP="slow:sql" rspec ...运行上面命令之后,最慢的测试用例组(及测试用例,如果配置的话)就会用 slow: :sql 的 tag 进行标识。
自定义测量器
要让 EventProf 和你的测量器引擎一起使用,只用完成下面两步:
- 为你的测量器添加一个封装器:
# Wrapper over your instrumentation
module MyEventsWrapper
# Should contain the only one method
def self.subscribe(event)
raise ArgumentError, "Block is required!" unless block_given?
::MyEvents.subscribe(event) do |start, finish, *|
yield (finish - start)
end
end
end- 在配置中设定测量器:
TestProf::EventProf.configure do |config|
config.instrumenter = MyEventsWrapper
end自定义事件
"factory.create"
FactoryGirl 提供了两个它自己的测量器(factory_girl.run_factory),但有一个警告——每次一个 factory 被使用时就会触发一个事件,即使我们是为嵌套关联关系使用 factory。因此由于重复计算这就不可能计算 factories 所耗费的时间了。
EventProf 为 FactoryGirl 带来了一个小的补丁,其仅为 top-level 的 FactoryGirl.create 调用提供测量器。如果你使用 "factory.create" 事件,它会自动加载:
EVENT_PROF=factory.create bundle exec rspec自 v0.9.0 起
也支持 Fabrication(追踪隐式和显式的 Fabricate.create 调用)。
"sidekiq.jobs"
收集关于 inline 运行的 Sidekiq jobs 的统计数字:
EVENT_PROF=sidekiq.jobs bundle exec rspec注意: 会自动把 rank_by 设为 count(因为收集耗费时间的信息没有意义——参看下边)。
"sidekiq.inline"
收集关于 inline 运行的 Sidekiq jobs 的统计数字(除去嵌套 jobs):
EVENT_PROF=sidekiq.inline bundle exec rspec使用该事件来分析正在运行的 Sidekiq jobs 的耗费时间。
分析任意方法
你也可以添加自定义事件来分析特定的方法(例如,在用 RubyProf 或 StackProf找出一些最热的调用后)。
比如,有个 class 做了些很繁重的工作:
class Work
def do_smth(*args)
# do something
end
end你可以通过添加一个 monitor 来分析:
# provide a class, event name and methods to monitor
TestProf::EventProf.monitor(Work, "my.work", :do_smth)然后象平常一样运行 EventProf:
EVENT_PROF=my.work bundle exec rake test自 v0.9.0 起
你也可以提供额外的选项:
top_level: true | false(默认为false):定义是否只考虑 top-level 调用并忽略此事件的嵌套触发器(这正是 "factory.create" 如何实现的)。guard: Proc(默认为nil): 提供一个 Proc,防止触发一个事件:仅当guard返回true时方法才被测量;guard使用instance_exec执行,并将方法参数传递给它。
例如:
TestProf::EventProf.monitor(
Sidekiq::Client,
"sidekiq.inline",
:raw_push,
top_level: true,
guard: ->(*) { Sidekiq::Testing.inline? }
)你可以根据_需要_添加 monitors(比如仅当你想要追踪特定事件时),通过把代码封装到 TestProf::EventProf::CustomEvents.register方法内:
TestProf::EventProf::CustomEvents.register("my.work") do
TestProf::EventProf.monitor(Work, "my.work", :do_smth)
end
# Then call `activate_all` with the provided event
TestProf::EventProf::CustomEvents.activate_all(TestProf::EventProf.config.event)这个 block 仅当特定事件在 EventProf 被启动时才执行。