Quick Test Hack of the Day

Ovid on 2008-03-04T12:05:44

As part of our ongoing effort to maintain our test suite's performance, I've just added the following quick hack to source control (it needs a lot of work):

#!/usr/bin/env perl

use strict;
use warnings;
use App::Prove::State;
use List::Util 'sum';
use Lingua::EN::Numbers 'num2en';

my $prove = '.prove';
unless (-f $prove && -r _) {
    die "Cannot find or read $prove file";
}

my $state      = App::Prove::State->new({ store => $prove });
my $generation = $state->{_}{generation};
my $tests      = $state->{_}{tests};

my $total   = sum(map { $_->{elapsed} } values %$tests);
my $minutes = int($total / 60);
my $seconds = int($total % 60);

my $num_tests = shift || 5;

if ($num_tests > keys %$tests) {
    $num_tests = keys %$tests;
}

my $num_word = num2en($num_tests);

my %time_for;
while (my ($test, $data) = each %$tests) {
    $time_for{$test} = $data->{elapsed};
}

my @sorted_by_time_desc
        = sort { $time_for{$b} <=> $time_for{$a} } keys %time_for;

print "Generation $generation\n";
print "Total runtime approximately $minutes minutes $seconds seconds\n";
print "\u$num_word slowest tests:\n";
for (0 .. $num_tests) {
    my $test = $sorted_by_time_desc[$_];
    print "\t$time_for{$test} seconds -> $test\n";
}

Basically, if you use the '--state=save' option with prove, it will save the state of your tests in a .prove file. This code reads the file, tells you which generation the file is, total test suite run time in minutes and seconds and your 5 slowest tests. Pass it a number and it will tell you the X slowest tests.

Update. Here's the output from the current branch I'm working on (a slightly updated version from above):

Generation 18
Number of test programs: 58
Total runtime approximately 17 minutes 35 seconds
Five slowest tests:
        482.732247114182 seconds -> t/acceptance.t
        234.499103069305 seconds -> t/aggregate.t
        96.313854932785 seconds -> t/standards/strict.t
        66.6500070095062 seconds -> t/unit/db/migrations.t
        56.7010760307312 seconds -> t/unit/piptest/pprove/testdb.t
        13.5212490558624 seconds -> t/unit/api/builder/brand-promotions.t


Magic!

AndyArmstrong on 2008-03-04T12:21:07

That's great. I've just dumped it in my ~/bin as slowt. Thanks ;)

loop bug

esobchenko on 2008-03-05T09:14:04

actually last for() loop should start from 1, not from 0.

I'm confused

Ovid on 2008-03-05T12:19:57

I'm not sure I understand why. Arrays in Perl are indexed from 0, not 1, so that would skip the longest running test. Did I misunderstand you?

Re:I'm confused

fireartist on 2008-03-05T13:51:50

It's currently printing 6 lines when `$num_tests = 5`

Should it maybe be `for (0 .. $num_tests-1)` ?

Re:I'm confused

Ovid on 2008-03-05T13:56:51

Oh, duh :)