<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Segment7: Test Profiling by Lines Logged</title>
    <link>http://blog.segment7.net/articles/2007/01/22/test-profiling-by-lines-logged</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>The Blog</description>
    <item>
      <title>Test Profiling by Lines Logged</title>
      <description>&lt;p&gt;At work I've been cleaning up the tests and trying to make them run faster.  One way of doing this is profiling the tests and fixing the slow spots.  That only works so well, especially if there's lots of duplication or extra work in the tests.  With Rails you can go about this a different way, since you have a second source of information on your tests' operation, the log file.

&lt;p&gt;I added the following code to test/test_helper.rb:

&lt;pre&gt;&lt;code&gt;raise 'require\'d test/test_helper twice!, you broke it!' if
  ENV['RAILS_ENV'] == 'test'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the very top, even above &lt;code&gt;ENV["RALIS_ENV"] = "test"&lt;/code&gt; to make sure that the hack to Test::Unit::TestCase below happens only once, then the magic to figure out which test outputs which log lines:

&lt;pre&gt;&lt;code&gt;class Test::Unit::TestCase
  alias unlogged_run run
  def run(result, &amp;block)
    RAILS_DEFAULT_LOGGER.debug "RUNNING #{self.class} #{@method_name}"
    unlogged_run result, &amp;block
  end
end if ENV['PROFILE_LOG']&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each test run will be prefixed with text like &lt;samp&gt;RUNNING SomeTest test_blah&lt;/samp&gt; which I can then run this script on:

&lt;pre&gt;&lt;code&gt;#!/usr/local/bin/ruby -w

test = nil
tests = Hash.new 0

File.open 'log/test.log' do |fp|
  fp.each_line do |line|
    if line.strip =~ /^RUNNING (.*)/ then
      test = $1
    else
      tests[test] += 1
    end
  end
end

tests.sort_by { |test, count| -count }.each do |test, count|
  puts "%5d %s" % [count, test]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To get the profile information, I run:

&lt;pre&gt;&lt;kbd&gt;rake log:clear; PROFILE_LOG=y rake &amp;&amp; script/count_logs&lt;/kbd&gt;&lt;/pre&gt;

&lt;p&gt;When run on Firebrigade, I get the following output (top 10 only):

&lt;pre&gt;&lt;samp&gt;  130 ProjectViewTest test_show
   74 DummyControllerTest test_error_500
   59 OwnerTest test_class_owner_count
   42 ProjectControllerTest test_index
   39 HomeControllerTest test_index_no_builds
   38 RestControllerTest test_add_build
   35 ProjectControllerTest test_show_no_versions
   35 ProjectControllerTest test_search_many_matches
   34 RestControllerTest test_add_project
   33 RestControllerTest test_add_version&lt;/samp&gt;&lt;/pre&gt;

&lt;p&gt;Now I can quickly discover good candidates for refactoring.  #test_error_500 above dumps an email into the logs, so it is a bogus result.  That leaves ProjectViewTest#test_show as a candidate for simplification or refactoring.
</description>
      <pubDate>Mon, 22 Jan 2007 15:41:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:b6903db7-8561-4b4e-8a9e-8ed3e993bef2</guid>
      <author>drbrain@segment7.net (Eric Hodel)</author>
      <link>http://blog.segment7.net/articles/2007/01/22/test-profiling-by-lines-logged</link>
      <category>Rails</category>
      <category>Ruby</category>
      <category>Testing</category>
    </item>
    <item>
      <title>"Test Profiling by Lines Logged" by Eric Hodel</title>
      <description>&lt;p&gt;String#% was stolen from Python and works like String#sprintf.  It gets parsed as &lt;code&gt;puts("%5d %s" % [count, test])&lt;/code&gt;.&lt;/p&gt;</description>
      <pubDate>Tue, 23 Jan 2007 16:22:45 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:9f947313-bf74-43c6-8b41-dda40252c12f</guid>
      <link>http://blog.segment7.net/articles/2007/01/22/test-profiling-by-lines-logged#comment-682</link>
    </item>
    <item>
      <title>"Test Profiling by Lines Logged" by Joe Van Dyk</title>
      <description>&lt;p&gt;Huh, neat.  I&amp;#8217;ve not seen this syntax before:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;puts "%5d %s" % [count, test]&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;How does that magic work?  I don&amp;#8217;t see commas in between the function arguments.&lt;/p&gt;</description>
      <pubDate>Tue, 23 Jan 2007 14:56:27 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:845768b1-4ba5-4419-8b79-76e4161eb279</guid>
      <link>http://blog.segment7.net/articles/2007/01/22/test-profiling-by-lines-logged#comment-681</link>
    </item>
  </channel>
</rss>
