timed_specs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/lib/timed_specs/version.rb +1 -0
- data/lib/timed_specs.rb +75 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/time_specs_spec.rb +201 -0
- data/timed_specs.gemspec +22 -0
- metadata +82 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
VERSION = "0.0.1"
|
data/lib/timed_specs.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'rspec/core/formatters/documentation_formatter'
|
2
|
+
|
3
|
+
|
4
|
+
class TimedSpecs < RSpec::Core::Formatters::DocumentationFormatter
|
5
|
+
SLOWEST_EXAMPLES_COUNT = (ENV['SLOWEST_EXAMPLES_COUNT'] || 20).to_i
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@examples_with_execution_time = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def start(*args)
|
13
|
+
@output.puts "Time Specs Enabled"
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def example_group_started(*args)
|
18
|
+
@group_time = Time.now
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def example_group_finished(*args)
|
23
|
+
super
|
24
|
+
if @group_time
|
25
|
+
output.puts current_indentation + white("#{(Time.now - @group_time).round(3)}s")
|
26
|
+
@group_time = nil
|
27
|
+
else
|
28
|
+
output.puts
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Overridden method of the base documentation formatter
|
33
|
+
# Is executed after each passed example
|
34
|
+
def example_passed(example)
|
35
|
+
super(example)
|
36
|
+
@examples_with_execution_time << [
|
37
|
+
example.description,
|
38
|
+
example.metadata[:execution_result][:run_time], # this is the time taken to execute the example
|
39
|
+
format_caller(example.location) # relative path to the example file
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Overridden method of the base documentation formatter
|
44
|
+
# Used by DocumentationFormatter to display the example info after each passed example
|
45
|
+
# super - displays the example description
|
46
|
+
# Then display the execution time beside it
|
47
|
+
def passed_output(example)
|
48
|
+
super + cyan(" : #{example.metadata[:execution_result][:run_time].round(3)}s")
|
49
|
+
end
|
50
|
+
|
51
|
+
def start_dump
|
52
|
+
output_slowest_examples unless @examples_with_execution_time.empty?
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def output_slowest_examples
|
59
|
+
output.puts bold("\n\nSlowest examples:\n")
|
60
|
+
|
61
|
+
sort_by_run_time(@examples_with_execution_time)[0..SLOWEST_EXAMPLES_COUNT-1].each do |example|
|
62
|
+
output_slow_example(example)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def output_slow_example(example)
|
67
|
+
output.puts "#{bold(example[1].round(4))} #{example[0]}"
|
68
|
+
output.puts " " + cyan("# #{example[2]}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def sort_by_run_time(examples)
|
72
|
+
# example[1] = example_run_time
|
73
|
+
examples.sort{|x,y| y[1] <=> x[1] }
|
74
|
+
end
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
|
+
require 'pry'
|
4
|
+
require 'timed_specs'
|
5
|
+
|
6
|
+
# To properly reset the value of constants
|
7
|
+
# Extracted from: http://digitaldumptruck.jotabout.com/?p=551
|
8
|
+
def with_constants(constants)
|
9
|
+
saved_constants = {}
|
10
|
+
|
11
|
+
begin
|
12
|
+
constants.each do |constant, val|
|
13
|
+
saved_constants[constant] = TimedSpecs.const_get( constant )
|
14
|
+
without_warnings { TimedSpecs.const_set(constant, val) }
|
15
|
+
end
|
16
|
+
yield
|
17
|
+
ensure
|
18
|
+
saved_constants.each do |constant, val|
|
19
|
+
without_warnings { TimedSpecs.const_set(constant, val) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Assigning a value to a constant generates a warning which is supressed by this method
|
25
|
+
def without_warnings
|
26
|
+
original_verbosity = $VERBOSE
|
27
|
+
begin
|
28
|
+
$VERBOSE = nil
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
$VERBOSE = original_verbosity
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TimedSpecs do
|
4
|
+
|
5
|
+
let(:output) { StringIO.new }
|
6
|
+
let(:formatter) { TimedSpecs.new(output) }
|
7
|
+
let(:example_group){ RSpec::Core::ExampleGroup.describe("dummy example group") }
|
8
|
+
|
9
|
+
context "when initialized" do
|
10
|
+
describe "@examples_with_execution_time" do
|
11
|
+
it "should be initialized" do
|
12
|
+
formatter.instance_variables.should include(:@examples_with_execution_time)
|
13
|
+
end
|
14
|
+
it "should be an empty array" do
|
15
|
+
formatter.instance_variable_get("@examples_with_execution_time").should eq([])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#start" do
|
21
|
+
context "output" do
|
22
|
+
before do
|
23
|
+
formatter.start(0)
|
24
|
+
end
|
25
|
+
specify{ formatter.output.string.should include("Time Specs Enabled") }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#example_group_started" do
|
30
|
+
before do
|
31
|
+
@current_time = Time.now + 50
|
32
|
+
Time.stub(:now).and_return(@current_time)
|
33
|
+
formatter.example_group_started(example_group)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should initialize @group_time" do
|
37
|
+
formatter.instance_variables.should include(:@group_time)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should set @group_time to the current time" do
|
41
|
+
formatter.instance_variable_get("@group_time").should eq(@current_time)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#example_group_finished" do
|
47
|
+
context "when @group_time is set" do
|
48
|
+
before do
|
49
|
+
@time1 = Time.now
|
50
|
+
@time2 = Time.now + 10
|
51
|
+
Time.stub(:now).and_return(@time2)
|
52
|
+
formatter.stub(:current_indentation).and_return("###")
|
53
|
+
formatter.instance_variable_set("@group_time", @time1)
|
54
|
+
formatter.example_group_finished(example_group)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should reset @group_time" do
|
58
|
+
formatter.instance_variable_get("@group_time").should be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
context "output" do
|
62
|
+
subject{ formatter.output.string }
|
63
|
+
it "should include the group time" do
|
64
|
+
subject.should include((@time2 - @time1).round(3).to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should include the current indentation" do
|
68
|
+
subject.should include("###")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when @group_time is not set" do
|
74
|
+
specify{ expect{formatter.example_group_finished(example_group)}.to_not raise_error }
|
75
|
+
context "output" do
|
76
|
+
before do
|
77
|
+
formatter.example_group_finished(example_group)
|
78
|
+
end
|
79
|
+
subject{ formatter.output.string }
|
80
|
+
it{ should include("\n") }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#example_passed" do
|
86
|
+
let(:example){
|
87
|
+
double(
|
88
|
+
"dummy example",
|
89
|
+
:description => "my dummy example",
|
90
|
+
:metadata => {
|
91
|
+
:execution_result => {:status => 'passed', :exception => Exception.new , :run_time => 1.1234}
|
92
|
+
},
|
93
|
+
:location => "location_to_the_example"
|
94
|
+
)
|
95
|
+
}
|
96
|
+
|
97
|
+
before do
|
98
|
+
formatter.stub(:format_caller).with("location_to_the_example").and_return("formatted_location_to_the_example")
|
99
|
+
formatter.example_passed(example)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should store the example in @examples_with_execution_time" do
|
103
|
+
formatter.instance_variable_get("@examples_with_execution_time").length.should eq(1)
|
104
|
+
end
|
105
|
+
|
106
|
+
context "the stored example" do
|
107
|
+
subject{ formatter.instance_variable_get("@examples_with_execution_time").first }
|
108
|
+
|
109
|
+
it{ should be_an(Array) }
|
110
|
+
|
111
|
+
it "should contain the description" do
|
112
|
+
subject[0].should eq("my dummy example")
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should contain the execution time" do
|
116
|
+
subject[1].should eq(1.1234)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should contain the formatted location" do
|
120
|
+
subject[2].should eq("formatted_location_to_the_example")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "output" do
|
125
|
+
subject{ formatter.output.string }
|
126
|
+
|
127
|
+
it{ should include(formatter.send(:cyan," : 1.123s")) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#start_dump" do
|
132
|
+
context "when there are no examples" do
|
133
|
+
it "should not attempt to display the slowest examples" do
|
134
|
+
formatter.should_receive(:output_slowest_examples).exactly(0).times
|
135
|
+
formatter.start_dump
|
136
|
+
end
|
137
|
+
end
|
138
|
+
context "when there are some examples" do
|
139
|
+
it "should display the slowest examples" do
|
140
|
+
formatter.instance_variable_set("@examples_with_execution_time", [1])
|
141
|
+
formatter.should_receive(:output_slowest_examples).once.and_return(true)
|
142
|
+
formatter.start_dump
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#output_slowest_examples" do
|
148
|
+
let(:examples_with_execution_time){
|
149
|
+
5.times.map{|x| ["example#{x}", rand(1000)/rand(1000).to_f, "location_to_example#{x}"] }
|
150
|
+
}
|
151
|
+
before do
|
152
|
+
formatter.instance_variable_set("@examples_with_execution_time", examples_with_execution_time)
|
153
|
+
end
|
154
|
+
context "output" do
|
155
|
+
it "should contain the slowest examples heading" do
|
156
|
+
formatter.send("output_slowest_examples")
|
157
|
+
formatter.output.string.should include("Slowest examples:")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
context "when the SLOWEST_EXAMPLES_COUNT is greater than the examples count" do
|
161
|
+
it "should show the times for all the examples" do
|
162
|
+
formatter.should_receive(:output_slow_example).exactly(5).times.and_return(true)
|
163
|
+
formatter.send("output_slowest_examples")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when the SLOWEST_EXAMPLES_COUNT is less than the examples count" do
|
168
|
+
it "should only show the SLOWEST_EXAMPLES_COUNT number of examples" do
|
169
|
+
formatter.should_receive(:output_slow_example).exactly(2).times.and_return(true)
|
170
|
+
with_constants :SLOWEST_EXAMPLES_COUNT => 2 do
|
171
|
+
formatter.send("output_slowest_examples")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#output_slow_example" do
|
178
|
+
let(:slow_example){ ["example1", 1.23456, "location_to_example1"] }
|
179
|
+
before do
|
180
|
+
formatter.send("output_slow_example", slow_example)
|
181
|
+
end
|
182
|
+
context "output" do
|
183
|
+
subject{ formatter.output.string }
|
184
|
+
|
185
|
+
it{ should include("example1"), "should include the example description" }
|
186
|
+
it{ should include(formatter.send(:bold, "1.2346")), "should include the example time" }
|
187
|
+
it{ should include(formatter.send(:cyan, "# location_to_example1")), "should include the example location" }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "#sort_by_run_time" do
|
192
|
+
it "should sort the items in descending order of the second element in the array" do
|
193
|
+
examples = 5.times.map{ [nil, rand(100), nil] }
|
194
|
+
sorted_examples = formatter.send("sort_by_run_time", examples)
|
195
|
+
|
196
|
+
sorted_examples[0..-2].each_index do |index|
|
197
|
+
sorted_examples[index][1].should be > sorted_examples[index + 1][1]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/timed_specs.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/timed_specs/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["dipil-saud"]
|
6
|
+
gem.email = ["dipil.saud@gmail.com"]
|
7
|
+
gem.description = %q{
|
8
|
+
A Rspec formatter built upon the default DocumentationFormatter which shows the time taken for each example along with the other information shown by the DocumentationFormatter. You also have the option to list the slowest 'n' examples at the end.
|
9
|
+
}
|
10
|
+
gem.summary = %q{A rspec formatter which displays the individual time taken by each example and lists the slowest examples. }
|
11
|
+
gem.homepage = ""
|
12
|
+
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
gem.name = "timed_specs"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = VERSION
|
19
|
+
|
20
|
+
gem.add_runtime_dependency "rspec"
|
21
|
+
gem.add_development_dependency "pry"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: timed_specs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- dipil-saud
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-31 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2165151740 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2165151740
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: pry
|
27
|
+
requirement: &2165151040 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2165151040
|
36
|
+
description: ! "\n A Rspec formatter built upon the default DocumentationFormatter
|
37
|
+
which shows the time taken for each example along with the other information shown
|
38
|
+
by the DocumentationFormatter. You also have the option to list the slowest 'n'
|
39
|
+
examples at the end.\n "
|
40
|
+
email:
|
41
|
+
- dipil.saud@gmail.com
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Gemfile
|
48
|
+
- Rakefile
|
49
|
+
- lib/timed_specs.rb
|
50
|
+
- lib/timed_specs/version.rb
|
51
|
+
- spec/spec_helper.rb
|
52
|
+
- spec/time_specs_spec.rb
|
53
|
+
- timed_specs.gemspec
|
54
|
+
homepage: ''
|
55
|
+
licenses: []
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.8.10
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: A rspec formatter which displays the individual time taken by each example
|
78
|
+
and lists the slowest examples.
|
79
|
+
test_files:
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- spec/time_specs_spec.rb
|
82
|
+
has_rdoc:
|