Search code examples
ruby-on-railsrubyrspecrspec2

How to get the current test filename from RSpec?


I'm trying to speed up a large RSpec project's tests. In addition to using RSpec's --profile option I wanted to get the longest running test files [1] printed out.

In my spec_helper.rb I dump the classes being tested and total time to a file, however as we have spec/model and spec/request directories I'd really like to be able to print the current test's filename and not just the class name (described_class), so that the user can disambiguate between model/foo_spec.rb and request/foo_spec.rb when optimizing.

In a before block in the spec/spec_helper.rb, how can I get the current test file's filename?

My (heavily trimmed) spec_helper looks like this:

config.before :all do
  @start_time = Time.now
end

config.after :all do |test|
  timings.push({ :name => test.described_class,
                 :file => 'I do not know how to get this',
                 :duration_in_seconds => (Time.now - @start_time) })
end

config.after :suite do
  timing_logfile_name = 'log/rspec_file_times.log'
  timing_logfile = "#{File.dirname(__FILE__)}/../#{timing_logfile_name}"
  file = File.open(timing_logfile, 'w')
  timings.sort_by{ |timing| timing[:duration_in_seconds].to_f }.reverse!.each do |timing|
    file.write( sprintf("%-25.25s    % 9.3f seconds\n",
                        timing[:name], timing[:duration_in_seconds]) )
  end
  file.close
  tell_if_verbose("Overall test times are logged in '#{timing_logfile_name}'")
end

This doesn't seem to be available in the curretn RSpec meta-data, but I'm hoping someone more familiar with the internals can think of a way to expose it. Thanks, Dave

[1] Often a file with, say, 100 examples in it yields more speed up than a single example from --profile - when that large file's before :each / before :all blocks are targetted, obviously even a ms saved is multiplied up by the number of tests in the file. Using this technique in addition to --profile helped me a lot.


Solution

  • As long as you're just using this for profiling your tests to identify which files need to be improved, you should be able to toss this into your spec_helper.rb file (and remove it afterwards). I fully understand that this is not pretty/clean/elegant/acceptible in production environments and I disavow that I ever wrote it :)

    config.before(:each) do |example|
      path = example.metadata[:example_group][:file_path]
      curr_path = config.instance_variable_get(:@curr_file_path)
      if (curr_path.nil? || path != curr_path)
        config.instance_variable_set(:@curr_file_path, path)
        puts path
      end
    end