test-prof 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +4 -8
  4. data/guides/any_fixture.md +1 -1
  5. data/guides/before_all.md +2 -2
  6. data/guides/event_prof.md +2 -2
  7. data/guides/factory_default.md +4 -4
  8. data/guides/factory_doctor.md +48 -3
  9. data/guides/factory_prof.md +5 -5
  10. data/guides/let_it_be.md +3 -2
  11. data/guides/rspec_dissect.md +3 -1
  12. data/guides/rspec_stamp.md +4 -5
  13. data/guides/rubocop.md +4 -4
  14. data/guides/ruby_prof.md +1 -1
  15. data/guides/stack_prof.md +3 -3
  16. data/lib/minitest/base_reporter.rb +57 -0
  17. data/lib/{test_prof/event_prof/formatters/minitest.rb → minitest/event_prof_formatter.rb} +6 -6
  18. data/lib/minitest/fd_ignorable.rb +13 -0
  19. data/lib/minitest/test_prof_plugin.rb +43 -0
  20. data/lib/test_prof.rb +3 -3
  21. data/lib/test_prof/event_prof/minitest.rb +51 -69
  22. data/lib/test_prof/event_prof/rspec.rb +8 -1
  23. data/lib/test_prof/factory_doctor.rb +1 -5
  24. data/lib/test_prof/factory_doctor/minitest.rb +84 -1
  25. data/lib/test_prof/factory_doctor/rspec.rb +10 -1
  26. data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +3 -3
  27. data/lib/test_prof/factory_prof/factory_builders/factory_girl.rb +3 -2
  28. data/lib/test_prof/factory_prof/printers/flamegraph.rb +1 -0
  29. data/lib/test_prof/factory_prof/printers/simple.rb +1 -0
  30. data/lib/test_prof/logging.rb +1 -0
  31. data/lib/test_prof/recipes/rspec/let_it_be.rb +11 -0
  32. data/lib/test_prof/recipes/rspec/sample.rb +2 -2
  33. data/lib/test_prof/rspec_dissect.rb +10 -2
  34. data/lib/test_prof/rspec_dissect/rspec.rb +27 -11
  35. data/lib/test_prof/tag_prof/rspec.rb +6 -3
  36. data/lib/test_prof/version.rb +1 -1
  37. metadata +7 -5
  38. data/lib/minitest/event_prof_plugin.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d45463f21e439e42506d700ace1dcc6202869ee8
4
- data.tar.gz: 1f6cd4e4a1161cfacda3f6f95371408131e4e49f
3
+ metadata.gz: 6efa575090e0c535e962071ed5b24a0d5f9f360b
4
+ data.tar.gz: c60d25f31f5450a7b926845711527531ac595c3c
5
5
  SHA512:
6
- metadata.gz: 816ca6fed6eb159671eb0563294daae38ec832e7a6530eec7c6cefe16bf66d96d7014c5d3a110a3c207f0cbaa49425cab335fc41b5d7be557e2ad07aee5753ae
7
- data.tar.gz: a22cd5e4f92f5e47918132d5646a53593a756cfb27fb88f00152d8e58ca6ec8f0479893f99698cd50f9c4ee26da79ba04351498552224b745a4b0f9376a17179
6
+ metadata.gz: c4d148c53dd4807ede82768a7e779d56bfcfb04a8ac9ed6f8eb3aa260fbbe753e64dd79a9c021093442fcfb981d9e2a846c2450482c6ffb84c68d05ef336c620
7
+ data.tar.gz: 5aa0611fe30a98061f0d9a97bf7a09066614a3663e845e99cc510697f29d847c581183b75d89e9ea0cfa92ea93048249780fe77fdd6d4e87b25eacc9b29576fe
@@ -1,5 +1,19 @@
1
1
  # Change log
2
2
 
3
+ ## 0.4.1
4
+
5
+ - [#44](https://github.com/palkan/test-prof/pull/44) Suppor older versions of RSpec. ([@palkan][])
6
+
7
+ Support RSpec 3.1.0+ in general.
8
+
9
+ `let_it_be` supports only RSpec 3.3.0+.
10
+
11
+ RSpecDissect `let` tracking supports only RSpec 3.3.0+.
12
+
13
+ - [#38](https://github.com/palkan/test-prof/pull/38) Factory Doctor Minitest integration. ([@IDolgirev][])
14
+
15
+ It is possible now to use Factory Doctor with Minitest
16
+
3
17
  ## 0.4.0
4
18
 
5
19
  ### Features:
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  TestProf is a collection of different tools to analyze your test suite performance.
6
6
 
7
- Why does test suite performance matter? First of all, testing is a part of a developer's feedback loop (see @searls [talk](https://www.youtube.com/watch?v=VD51AkG8EZw)) and, secondly, it is a part of a deployment cycle.
7
+ Why does test suite performance matter? First of all, testing is a part of a developer's feedback loop (see [@searls](https://github.com/searls) [talk](https://vimeo.com/145917204)) and, secondly, it is a part of a deployment cycle.
8
8
 
9
9
  Simply speaking, slow tests waste your time making you less productive.
10
10
 
@@ -16,7 +16,7 @@ TestProf toolbox aims to help you identify bottlenecks in your test suite. It co
16
16
 
17
17
  - ActiveSupport-backed profilers
18
18
 
19
- - Rubocop cops
19
+ - RuboCop cops
20
20
 
21
21
  - etc.
22
22
 
@@ -73,7 +73,7 @@ Checkout our guides for each specific tool:
73
73
 
74
74
  - [RSpecDissect Profiler](https://github.com/palkan/test-prof/tree/master/guides/rspec_dissect.md)
75
75
 
76
- - [Rubocop Cops](https://github.com/palkan/test-prof/tree/master/guides/rubocop.md)
76
+ - [RuboCop cops](https://github.com/palkan/test-prof/tree/master/guides/rubocop.md)
77
77
 
78
78
  ## Tips and Tricks (or _Recipes_)
79
79
 
@@ -110,13 +110,9 @@ end
110
110
 
111
111
  ## What's next?
112
112
 
113
- Or TODO list:
114
113
 
115
- - Better Minitest integration (PRs welcome!)
114
+ Have an idea? [Propose](https://github.com/palkan/test-prof/issues/new) a feature request!
116
115
 
117
- - Improve FactoryDoctor
118
-
119
- - Add more Rubocop cops (e.g. `CreateListLimit`)
120
116
 
121
117
  ## License
122
118
 
@@ -112,4 +112,4 @@ include_context "article"
112
112
  include_context "author"
113
113
  ```
114
114
 
115
- Now we have the following affected tables list: `["articles", "authors"]`. At the end of the suite, the "authors" table is cleaned first which leads to a foreign-key violation error.
115
+ Now we have the following affected tables list: `['articles', 'authors']`. At the end of the suite, the 'authors' table is cleaned first which leads to a foreign-key violation error.
@@ -34,7 +34,7 @@ describe BeatleWeightedSearchQuery do
34
34
  end
35
35
  ```
36
36
 
37
- But then you have to deal with database cleaning, which can be eigher tricky or slow.
37
+ But then you have to deal with database cleaning, which can be either tricky or slow.
38
38
 
39
39
  There is a better option: we can wrap the whole example group into a transaction.
40
40
  And that's how `before_all` works:
@@ -95,4 +95,4 @@ end
95
95
  # Note, that @user.reload may not be enough,
96
96
  # 'cause it doesn't reset associations
97
97
  let(:user) { User.find(@user.id) }
98
- ```
98
+ ```
@@ -34,7 +34,7 @@ Currently, EventProf supports only ActiveSupport::Notifications
34
34
 
35
35
  To activate EventProf with:
36
36
 
37
- ### Rspec
37
+ ### RSpec
38
38
 
39
39
  Use `EVENT_PROF` environment variable set to event name:
40
40
 
@@ -95,7 +95,7 @@ end
95
95
 
96
96
  Or provide the `EVENT_PROF_EXAMPLES=1` env variable.
97
97
 
98
- Another useful configuration parameter – `rank_by`. It's responsible for sorting stats –
98
+ Another useful configuration parameter – `rank_by`. It's responsible for sorting stats –
99
99
  either by the time spent in the event or by the number of occurrences:
100
100
 
101
101
  ```sh
@@ -1,6 +1,6 @@
1
1
  # FactoryDefault
2
2
 
3
- _Factory Default_ aims to help you cope with _factory cascades_ (see [FactoryProf](https://github.com/palkan/test-prof/tree/master/guides/factory_prof.md)) by re-using associated records.
3
+ _Factory Default_ aims to help you cope with _factory cascades_ (see [FactoryProf](https://github.com/palkan/test-prof/tree/master/guides/factory_prof.md)) by reusing associated records.
4
4
 
5
5
  It can be very useful when you're working on a typical SaaS application (or other hierarchical data).
6
6
 
@@ -51,7 +51,7 @@ Typical workaround:
51
51
  describe "PATCH #update" do
52
52
  let(:account) { create(:account) }
53
53
  let(:project) { create(:project, account: account) }
54
- let(:task( { create(:task, project: project, account: account) }
54
+ let(:task) { create(:task, project: project, account: account) }
55
55
 
56
56
  it "works" do
57
57
  patch :update, id: task.id, task: { completed: 't' }
@@ -68,9 +68,9 @@ Here is how we can deal with it using FactoryDefault:
68
68
  describe "PATCH #update" do
69
69
  let(:account) { create_default(:account) }
70
70
  let(:project) { create_default(:project) }
71
- let(:task( { create(:task) }
71
+ let(:task) { create(:task) }
72
72
 
73
- # and if need more projects, users, tasks with the same parent record,
73
+ # and if we need more projects, users, tasks with the same parent record,
74
74
  # we just write
75
75
  let(:another_project) { create(:project) } # uses the same account
76
76
  let(:another_task) { create(:task) } # uses the same account and the first project
@@ -37,12 +37,12 @@ User (./spec/models/user_spec.rb:3)
37
37
  validates email (./spec/user_spec.rb:8) – 2 records created, 00:00.514
38
38
  ```
39
39
 
40
- **NOTE**: have you noticed the "potentially" word? Unfortunately, FactoryDoctor is not a
40
+ **NOTE**: have you noticed the "potentially" word? Unfortunately, FactoryDoctor is not a
41
41
  magician (it's still learning) and sometimes it produces false negatives and false positives too.
42
42
 
43
43
  Please, submit an [issue](https://github.com/palkan/test-prof/issues) if you found a case which makes FactoryDoctor fail.
44
44
 
45
- You can also tell FactoryDoctor to ignore specific examples/groups. Just add `:fd_ignore` tag to it:
45
+ You can also tell FactoryDoctor to ignore specific examples/groups. Just add the `:fd_ignore` tag to it:
46
46
 
47
47
  ```ruby
48
48
  # won't be reported as offense
@@ -55,7 +55,9 @@ end
55
55
 
56
56
  ## Instructions
57
57
 
58
- Currently, FactoryDoctor works only with FactoryGirl and RSpec.
58
+ Currently, FactoryDoctor works only with FactoryGirl.
59
+
60
+ ## RSpec
59
61
 
60
62
  To activate FactoryDoctor use `FDOC` environment variable:
61
63
 
@@ -72,3 +74,46 @@ FDOC=1 FDOC_STAMP="fdoc:consider" rspec ...
72
74
  ```
73
75
 
74
76
  After running the command above all _potentially_ bad examples would be marked with the `fdoc: :consider` tag.
77
+
78
+ ## Minitest
79
+
80
+ To activate FactoryDoctor use `FDOC` environment variable:
81
+
82
+ ```sh
83
+ FDOC=1 ruby ...
84
+ ```
85
+
86
+ or use CLI option as shown below:
87
+
88
+ ```sh
89
+ ruby ... --factory-doctor
90
+ ```
91
+
92
+ The same option to force Factory Doctor to ignore specific examples is also available for Minitest.
93
+ Just use `fd_ignore` inside your example:
94
+
95
+ ```ruby
96
+ # won't be reported as offense
97
+ it "is ignored" do
98
+ fd_ignore
99
+
100
+ @user.name = ''
101
+ refute @user.valid?
102
+ end
103
+ ```
104
+
105
+ ## Using with Minitest::Reporters
106
+
107
+ If you're using `Minitest::Reporters` in your project you have to explicitly declare it
108
+ in your test helper file:
109
+
110
+ ```sh
111
+ require 'minitest/reporters'
112
+ Minitest::Reporters.use! [YOUR_FAVORITE_REPORTERS]
113
+ ```
114
+ #### NOTICE
115
+ When you have `minitest-reporters` installed as a gem but not declared in your `Gemfile`
116
+ make sure to always prepend your test run command with `bundle exec` (but we sure that you always do it).
117
+ Otherwise, you'll get an error caused by Minitest plugin system, which scans all the entries in the
118
+ `$LOAD_PATH` for any `minitest/*_plugin.rb`, thus initialization of `minitest-reporters` plugin which is
119
+ available in that case doesn't happens correctly.
@@ -16,7 +16,7 @@ Example output:
16
16
 
17
17
  It shows both the total number of the factory runs and the number of _top-level_ runs, i.e. not during another factory invocation (e.g. when using associations.)
18
18
 
19
- **NOTE**: FactoryProf only tracks the database-persisted factories. In case of FactoryFirl these are the factories
19
+ **NOTE**: FactoryProf only tracks the database-persisted factories. In case of FactoryGirl these are the factories
20
20
  provided by using `create` strategy. In case of Fabrication - objects that created using `create` method.
21
21
 
22
22
  ## Instructions
@@ -29,20 +29,20 @@ To activate FactoryProf use `FPROF` environment variable:
29
29
  # Simple profiler
30
30
  FPROF=1 rspec
31
31
 
32
- # or
32
+ # or
33
33
  FPROF=1 bundle exec rake test
34
34
  ```
35
35
 
36
36
  ## Factory Flamegraph
37
37
 
38
- The most useful feature of FactoryProf is the _FactoryFlame_ report. That's the special interpetation of Brendan Gregg's [flame graphs](http://www.brendangregg.com/flamegraphs.html) which allows you to identify _factory cascades_.
38
+ The most useful feature of FactoryProf is the _FactoryFlame_ report. That's the special interpretation of Brendan Gregg's [flame graphs](http://www.brendangregg.com/flamegraphs.html) which allows you to identify _factory cascades_.
39
39
 
40
40
  To generate FactoryFlame report set `FPROF` environment variable to `flamegraph`:
41
41
 
42
42
  ```sh
43
43
  FPROF=flamegraph rspec
44
44
 
45
- # or
45
+ # or
46
46
  FPROF=flamegraph bundle exec rake test
47
47
  ```
48
48
 
@@ -52,7 +52,7 @@ That's how a report looks like:
52
52
 
53
53
  How to read this?
54
54
 
55
- Every column represents a _factory stack_ or _cascade_, that is a sequence of recursive `#create` method calls. Consider and example:
55
+ Every column represents a _factory stack_ or _cascade_, that is a sequence of recursive `#create` method calls. Consider an example:
56
56
 
57
57
  ```ruby
58
58
  factory :comment do
@@ -11,7 +11,7 @@ describe BeatleWeightedSearchQuery do
11
11
  let!(:george) { create(:beatle, name: 'George') }
12
12
  let!(:john) { create(:beatle, name: 'John') }
13
13
 
14
- specify { expect(subject.call('joh')).to contain_exactly(john) }
14
+ specify { expect(subject.call('john')).to contain_exactly(john) }
15
15
 
16
16
  # and more examples here
17
17
  end
@@ -45,7 +45,7 @@ describe BeatleWeightedSearchQuery do
45
45
  let_it_be(:george) { create(:beatle, name: 'George') }
46
46
  let_it_be(:john) { create(:beatle, name: 'John') }
47
47
 
48
- specify { expect(subject.call('joh')).to contain_exactly(john) }
48
+ specify { expect(subject.call('john')).to contain_exactly(john) }
49
49
 
50
50
  # and more examples here
51
51
  end
@@ -53,6 +53,7 @@ end
53
53
 
54
54
  That's it! Just replace `let!` with `let_it_be`. That's equal to the `before_all` approach but requires less refactoring.
55
55
 
56
+ **NOTE**: requires RSpec >= 3.2.0.
56
57
 
57
58
  ## Instructions
58
59
 
@@ -1,6 +1,6 @@
1
1
  # RSpecDissect
2
2
 
3
- Do you know how much time you spend in `before` hooks? Or memoization helpers such as `let`? Usually, the most of the whole test suite time.
3
+ Do you know how much time you spend in `before` hooks? Or in memoization helpers such as `let`? Usually, the most of the whole test suite time.
4
4
 
5
5
  _RSpecDissect_ provides this kind of information and also shows you the worst example groups. The main purpose of RSpecDissect is to identify these slow groups and refactor them using [`before_all`](https://github.com/palkan/test-prof/tree/master/guides/before_all.md) or [`let_it_be`](https://github.com/palkan/test-prof/tree/master/guides/let_it_be.md) recipes.
6
6
 
@@ -31,6 +31,8 @@ BookedSlotsController (./spec/controllers/booked_slots_controller_spec.rb:3) –
31
31
  AvailableSlotsController (./spec/controllers/available_slots_controller_spec.rb:3) – 00:18.481 of 00:23.366 (85)
32
32
  ```
33
33
 
34
+ **NOTE**: Tracking `let` time only supported in RSpec >= 3.3.0.
35
+
34
36
  ## Instructions
35
37
 
36
38
  RSpecDissect can only be used with RSpec (which is clear from the name).
@@ -1,10 +1,10 @@
1
- # RSpec Stamp
1
+ # RSpecStamp
2
2
 
3
- RSpec Stamp is a tool to automatically _tag_ failed examples with custom tags.
3
+ RSpecStamp is a tool to automatically _tag_ failed examples with custom tags.
4
4
 
5
5
  It _literally_ adds tags to your examples (i.e. rewrites them).
6
6
 
7
- The main purpose of RSpec Stamp is to make refactoring testing codebase easy. Changing global configuration may cause a lot of failures. You can patch failing spec by adding a shared context. And here comes RSpec Stamp.
7
+ The main purpose of RSpecStamp is to make testing codebase refactoring easy. Changing global configuration may cause a lot of failures. You can patch failing spec by adding a shared context. And here comes RSpecStamp.
8
8
 
9
9
  ## Example Use Case: Sidekiq Inline
10
10
 
@@ -38,7 +38,7 @@ The output of the command above contains information about the _stamping_ proces
38
38
 
39
39
  Now all (or almost all) failing specs are tagged with `sidekiq: :inline`. Run the whole suite again and check it there are any failures left.
40
40
 
41
- There is also a _dry-run_ mode (activated by `RSTAMP_DRY_RUN=1` env variable) which prints out patches instead of re-writing files.
41
+ There is also a `dry-run` mode (activated by `RSTAMP_DRY_RUN=1` env variable) which prints out patches instead of re-writing files.
42
42
 
43
43
  ## Configuration
44
44
 
@@ -50,4 +50,3 @@ TestProf::RSpecStamp.configure do |config|
50
50
  config.ignore_files << %r{spec/my_directory}
51
51
  end
52
52
  ```
53
-
@@ -1,10 +1,10 @@
1
- # Custom Rubocop Cops
1
+ # Custom RuboCop Cops
2
2
 
3
- TestProf comes with the [Rubocop](https://github.com/bbatsov/rubocop) cops that help you write more performant tests.
3
+ TestProf comes with the [RuboCop](https://github.com/bbatsov/rubocop) cops that help you write more performant tests.
4
4
 
5
5
  To enable them:
6
6
 
7
- - Require `test_prof/rubocop` in your Rubocop configuration:
7
+ - Require `test_prof/rubocop` in your RuboCop configuration:
8
8
 
9
9
  ```yml
10
10
  # .rubocop.yml
@@ -21,7 +21,7 @@ RSpec/AggregateFailures:
21
21
  - 'spec/**/*.rb'
22
22
  ```
23
23
 
24
- ## Rspec/AggregateFailures
24
+ ## RSpec/AggregateFailures
25
25
 
26
26
  This cop encourages you to use one of the greatest features of the recent RSpec – aggregating failures within an example.
27
27
 
@@ -13,7 +13,7 @@ group :development, :test do
13
13
  end
14
14
  ```
15
15
 
16
- RubyProf profiler has two modes: _global_ and _per-example_.
16
+ RubyProf profiler has two modes: `global` and `per-example`.
17
17
 
18
18
  You can activate the global profiling using the environment variable `TEST_RUBY_PROF`:
19
19
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Instructions
6
6
 
7
- Install 'stackprof' gem (>= 0.2.9):
7
+ Install `stackprof` gem (>= 0.2.9):
8
8
 
9
9
  ```ruby
10
10
  # Gemfile
@@ -13,9 +13,9 @@ group :development, :test do
13
13
  end
14
14
  ```
15
15
 
16
- StackProf profiler has 2 modes: _global_ and _per-example_.
16
+ StackProf profiler has 2 modes: `global` and `per-example`.
17
17
 
18
- You can activate the global profiling using the environment variable `TEST_STACK_PROF`:
18
+ You can activate global profiling using the environment variable `TEST_STACK_PROF`:
19
19
 
20
20
  ```sh
21
21
  TEST_STACK_PROF=1 bundle exec rake test
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest'
4
+ require 'test_prof/logging'
5
+
6
+ module Minitest
7
+ module TestProf
8
+ class BaseReporter < AbstractReporter # :nodoc:
9
+ include ::TestProf::Logging
10
+
11
+ attr_accessor :io
12
+
13
+ def initialize(io = $stdout, _options = {})
14
+ @io = io
15
+ inject_to_minitest_reporters if defined? Minitest::Reporters
16
+ end
17
+
18
+ def start; end
19
+
20
+ def prerecord(group, example); end
21
+
22
+ def before_test(test); end
23
+
24
+ def record(*); end
25
+
26
+ def after_test(test); end
27
+
28
+ def report; end
29
+
30
+ private
31
+
32
+ def location(group, example = nil)
33
+ if group.is_a? Class
34
+ suite = group.public_instance_methods.select { |mtd| mtd.to_s.match /^test_/ }
35
+ name = suite.find { |mtd| mtd.to_s == example }
36
+ group.instance_method(name).source_location
37
+ else
38
+ suite = group.methods.select { |mtd| mtd.to_s.match /^test_/ }
39
+ name = suite.find { |mtd| mtd.to_s == group.name }
40
+ group.method(name).source_location
41
+ end
42
+ end
43
+
44
+ def location_with_line_number(group, example = nil)
45
+ File.expand_path(location(group, example).join(':')).gsub(Dir.getwd, '.')
46
+ end
47
+
48
+ def location_without_line_number(group, example = nil)
49
+ File.expand_path(location(group, example).first).gsub(Dir.getwd, '.')
50
+ end
51
+
52
+ def inject_to_minitest_reporters
53
+ Minitest::Reporters.reporters << self if Minitest::Reporters.reporters
54
+ end
55
+ end
56
+ end
57
+ end
@@ -4,12 +4,12 @@ require "test_prof/ext/float_duration"
4
4
  require "test_prof/ext/string_truncate"
5
5
  require "test_prof/ext/string_strip_heredoc"
6
6
 
7
- module TestProf
8
- module EventProf
9
- class MinitestFormatter # :nodoc:
10
- using FloatDuration
11
- using StringTruncate
12
- using StringStripHeredoc
7
+ module Minitest
8
+ module TestProf
9
+ class EventProfFormatter # :nodoc:
10
+ using ::TestProf::FloatDuration
11
+ using ::TestProf::StringTruncate
12
+ using ::TestProf::StringStripHeredoc
13
13
 
14
14
  def initialize(profiler)
15
15
  @profiler = profiler
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Minitest
4
+ module Assertions # :nodoc:
5
+ def fd_ignore
6
+ @fd_ignore = true
7
+ end
8
+
9
+ def fd_ignore?
10
+ @fd_ignore == true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_prof/event_prof/minitest'
4
+ require 'test_prof/factory_doctor/minitest'
5
+
6
+ module Minitest # :nodoc:
7
+ module TestProf # :nodoc:
8
+ def self.configure_options(options = {})
9
+ options.tap do |opts|
10
+ opts[:event] = ENV['EVENT_PROF'] if ENV['EVENT_PROF']
11
+ opts[:rank_by] = ENV['EVENT_PROF_RANK'].to_sym if ENV['EVENT_PROF_RANK']
12
+ opts[:top_count] = ENV['EVENT_PROF_TOP'].to_i if ENV['EVENT_PROF_TOP']
13
+ opts[:per_example] = true if ENV['EVENT_PROF_EXAMPLES']
14
+ opts[:fdoc] = true if ENV['FDOC']
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.plugin_test_prof_options(opts, options)
20
+ opts.on "--event-prof=EVENT", "Collects metrics for specified EVENT" do |event|
21
+ options[:event] = event
22
+ end
23
+ opts.on "--event-prof-rank-by=RANK_BY", "Defines RANK_BY parameter for results" do |rank|
24
+ options[:rank_by] = rank.to_sym
25
+ end
26
+ opts.on "--event-prof-top-count=N", "Limits results with N groups/examples" do |count|
27
+ options[:top_count] = count.to_i
28
+ end
29
+ opts.on "--event-prof-per-example", TrueClass, "Includes examples metrics to results" do |flag|
30
+ options[:per_example] = flag
31
+ end
32
+ opts.on "--factory-doctor", TrueClass, 'Enable Factory Doctor for your examples' do |flag|
33
+ options[:fdoc] = flag
34
+ end
35
+ end
36
+
37
+ def self.plugin_test_prof_init(options)
38
+ options = TestProf.configure_options(options)
39
+
40
+ reporter << TestProf::EventProfReporter.new(options[:io], options) if options[:event]
41
+ reporter << TestProf::FactoryDoctorReporter.new(options[:io], options) if options[:fdoc]
42
+ end
43
+ end
@@ -9,7 +9,7 @@ require "test_prof/utils"
9
9
  #
10
10
  # Contains tools to anylyze factories usage, integrate with Ruby profilers,
11
11
  # profile your examples using ActiveSupport notifications (if any) and
12
- # statically analyze your code with custom Rubocop cops.
12
+ # statically analyze your code with custom RuboCop cops.
13
13
  #
14
14
  # Example usage:
15
15
  #
@@ -47,11 +47,11 @@ module TestProf
47
47
 
48
48
  # Require gem and shows a custom
49
49
  # message if it fails to load
50
- def require(gem_name, msg)
50
+ def require(gem_name, msg = nil)
51
51
  Kernel.require gem_name
52
52
  block_given? ? yield : true
53
53
  rescue LoadError
54
- log :error, msg
54
+ log(:error, msg) if msg
55
55
  false
56
56
  end
57
57
 
@@ -1,90 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_prof/logging'
4
- require 'test_prof/event_prof/formatters/minitest'
3
+ require 'minitest/base_reporter'
4
+ require 'minitest/event_prof_formatter'
5
5
 
6
6
  module Minitest
7
- class EventProfReporter < AbstractReporter # :nodoc:
8
- include TestProf::Logging
9
-
10
- attr_accessor :io
11
-
12
- def initialize(io = $stdout, options = {})
13
- @io = io
14
- @profiler = configure_profiler(options)
15
- @formatter = TestProf::EventProf::MinitestFormatter.new(@profiler)
16
- @current_group = nil
17
- @current_example = nil
18
- inject_to_minitest_reporters if defined? Minitest::Reporters
19
- end
20
-
21
- def start; end
22
-
23
- def prerecord(group, example)
24
- change_current_group(group, example) unless @current_group
25
- track_current_example(group, example)
26
- end
27
-
28
- def before_test(test)
29
- prerecord(test.class, test.name)
30
- end
31
-
32
- def record(*)
33
- @profiler.example_finished(@current_example)
34
- end
7
+ module TestProf
8
+ class EventProfReporter < BaseReporter # :nodoc:
9
+ def initialize(io = $stdout, options = {})
10
+ super
11
+ @profiler = configure_profiler(options)
12
+ @formatter = EventProfFormatter.new(@profiler)
13
+ @current_group = nil
14
+ @current_example = nil
15
+ end
35
16
 
36
- def after_test(*); end
17
+ def prerecord(group, example)
18
+ change_current_group(group, example) unless @current_group
19
+ track_current_example(group, example)
20
+ end
37
21
 
38
- def report
39
- @profiler.group_finished(@current_group)
40
- result = @formatter.prepare_results
41
- puts "\n"
42
- log :info, result
43
- end
22
+ def before_test(test)
23
+ prerecord(test.class, test.name)
24
+ end
44
25
 
45
- private
26
+ def record(*)
27
+ @profiler.example_finished(@current_example)
28
+ end
46
29
 
47
- def track_current_example(group, example)
48
- unless @current_group[:name] == group.name
30
+ def report
49
31
  @profiler.group_finished(@current_group)
50
- change_current_group(group, example)
32
+ result = @formatter.prepare_results
33
+ log :info, result
51
34
  end
52
35
 
53
- @current_example = {
54
- name: example.gsub(/^test_(?:\d+_)?/, ''),
55
- location: File.expand_path(location(group, example).join(':')).gsub(Dir.getwd, '.')
56
- }
36
+ private
57
37
 
58
- @profiler.example_started(@current_example)
59
- end
38
+ def track_current_example(group, example)
39
+ unless @current_group[:name] == group.name
40
+ @profiler.group_finished(@current_group)
41
+ change_current_group(group, example)
42
+ end
60
43
 
61
- def change_current_group(group, example)
62
- @current_group = {
63
- name: group.name,
64
- location: File.expand_path(location(group, example).first).gsub(Dir.getwd, '.')
65
- }
44
+ @current_example = {
45
+ name: example.gsub(/^test_(?:\d+_)?/, ''),
46
+ location: location_with_line_number(group, example)
47
+ }
66
48
 
67
- @profiler.group_started(@current_group)
68
- end
49
+ @profiler.example_started(@current_example)
50
+ end
69
51
 
70
- def location(group, example)
71
- suite = group.public_instance_methods.select { |mtd| mtd.to_s.match /^test_/ }
72
- name = suite.find { |mtd| mtd.to_s == example }
73
- group.instance_method(name).source_location
74
- end
52
+ def change_current_group(group, example)
53
+ @current_group = {
54
+ name: group.name,
55
+ location: location_without_line_number(group, example)
56
+ }
75
57
 
76
- def configure_profiler(options)
77
- TestProf::EventProf.configure do |config|
78
- config.event = options[:event]
79
- config.rank_by = options[:rank_by] if options[:rank_by]
80
- config.top_count = options[:top_count] if options[:top_count]
81
- config.per_example = options[:per_example] if options[:per_example]
58
+ @profiler.group_started(@current_group)
82
59
  end
83
- TestProf::EventProf.build
84
- end
85
60
 
86
- def inject_to_minitest_reporters
87
- Minitest::Reporters.reporters << self if Minitest::Reporters.reporters
61
+ def configure_profiler(options)
62
+ ::TestProf::EventProf.configure do |config|
63
+ config.event = options[:event]
64
+ config.rank_by = options[:rank_by] if options[:rank_by]
65
+ config.top_count = options[:top_count] if options[:top_count]
66
+ config.per_example = options[:per_example] if options[:per_example]
67
+ end
68
+ ::TestProf::EventProf.build
69
+ end
88
70
  end
89
71
  end
90
72
  end
@@ -16,7 +16,9 @@ module TestProf
16
16
  example_group_started
17
17
  example_group_finished
18
18
  example_started
19
- example_finished
19
+ example_failed
20
+ example_passed
21
+ example_pending
20
22
  ].freeze
21
23
 
22
24
  def initialize
@@ -41,6 +43,11 @@ module TestProf
41
43
  @profiler.example_finished notification.example
42
44
  end
43
45
 
46
+ # NOTE: RSpec < 3.4.0 doesn't have example_finished event
47
+ alias example_passed example_finished
48
+ alias example_failed example_finished
49
+ alias example_pending example_finished
50
+
44
51
  def print
45
52
  result = @profiler.results
46
53
 
@@ -134,8 +134,4 @@ module TestProf
134
134
  end
135
135
 
136
136
  require "test_prof/factory_doctor/rspec" if defined?(RSpec::Core)
137
- require "test_prof/factory_doctor/minitest" if defined?(Minitest::Reporters)
138
-
139
- TestProf.activate('FDOC') do
140
- TestProf::FactoryDoctor.init
141
- end
137
+ require "test_prof/factory_doctor/minitest" if defined?(Minitest)
@@ -1,3 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: write Minitest reporter
3
+ require 'minitest/base_reporter'
4
+ require 'minitest/fd_ignorable'
5
+ require 'test_prof/factory_doctor'
6
+ require 'test_prof/ext/float_duration'
7
+ require 'test_prof/ext/string_strip_heredoc'
8
+
9
+ module Minitest
10
+ module TestProf
11
+ class FactoryDoctorReporter < BaseReporter # :nodoc:
12
+ using ::TestProf::FloatDuration
13
+ using ::TestProf::StringStripHeredoc
14
+
15
+ SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'.freeze
16
+
17
+ def initialize(io = $stdout, options = {})
18
+ super
19
+ ::TestProf::FactoryDoctor.init
20
+ @count = 0
21
+ @time = 0.0
22
+ @example_groups = Hash.new { |h, k| h[k] = [] }
23
+ end
24
+
25
+ def prerecord(_group, _example)
26
+ ::TestProf::FactoryDoctor.start
27
+ end
28
+
29
+ def record(example)
30
+ ::TestProf::FactoryDoctor.stop
31
+ return if example.skipped? || example.fd_ignore?
32
+
33
+ result = ::TestProf::FactoryDoctor.result
34
+ return unless result.bad?
35
+
36
+ group = {
37
+ description: example.class.name,
38
+ location: location_without_line_number(example)
39
+ }
40
+
41
+ @example_groups[group] << {
42
+ description: example.name.gsub(/^test_(?:\d+_)?/, ''),
43
+ location: location_with_line_number(example),
44
+ factories: result.count,
45
+ time: result.time
46
+ }
47
+
48
+ @count += 1
49
+ @time += result.time
50
+ end
51
+
52
+ def report
53
+ return log(:info, SUCCESS_MESSAGE) if @example_groups.empty?
54
+
55
+ msgs = []
56
+
57
+ msgs <<
58
+ <<-MSG.strip_heredoc
59
+ FactoryDoctor report
60
+
61
+ Total (potentially) bad examples: #{@count}
62
+ Total wasted time: #{@time.duration}
63
+
64
+ MSG
65
+
66
+ @example_groups.each do |group, examples|
67
+ msgs << "#{group[:description]} (#{group[:location]})\n"
68
+ examples.each do |ex|
69
+ msgs << " #{ex[:description]} (#{ex[:location]}) "\
70
+ "– #{pluralize_records(ex[:factories])} created, "\
71
+ "#{ex[:time].duration}\n"
72
+ end
73
+ msgs << "\n"
74
+ end
75
+
76
+ log :info, msgs.join
77
+ end
78
+
79
+ private
80
+
81
+ def pluralize_records(count)
82
+ count == 1 ? '1 record' : "#{count} records"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -14,7 +14,9 @@ module TestProf
14
14
 
15
15
  NOTIFICATIONS = %i[
16
16
  example_started
17
- example_finished
17
+ example_passed
18
+ example_failed
19
+ example_pending
18
20
  ].freeze
19
21
 
20
22
  def initialize
@@ -45,6 +47,11 @@ module TestProf
45
47
  @time += result.time
46
48
  end
47
49
 
50
+ # NOTE: RSpec < 3.4.0 doesn't have example_finished event
51
+ alias example_passed example_finished
52
+ alias example_failed example_finished
53
+ alias example_pending example_finished
54
+
48
55
  def print
49
56
  return log(:info, SUCCESS_MESSAGE) if @example_groups.empty?
50
57
 
@@ -118,6 +125,8 @@ end
118
125
 
119
126
  # Register FactoryDoctor listener
120
127
  TestProf.activate('FDOC') do
128
+ TestProf::FactoryDoctor.init
129
+
121
130
  RSpec.configure do |config|
122
131
  listener = TestProf::FactoryDoctor::RSpecListener.new
123
132
 
@@ -10,9 +10,9 @@ module TestProf
10
10
  class Fabrication
11
11
  # Monkey-patch Fabrication
12
12
  def self.patch
13
- TestProf.require 'fabrication', ""
14
- ::Fabricate.singleton_class.prepend(FabricationPatch) if
15
- defined?(::Fabrication)
13
+ TestProf.require 'fabrication' do
14
+ ::Fabricate.singleton_class.prepend(FabricationPatch)
15
+ end
16
16
  end
17
17
 
18
18
  def self.track(factory, &block)
@@ -10,8 +10,9 @@ module TestProf
10
10
  class FactoryGirl
11
11
  # Monkey-patch FactoryGirl
12
12
  def self.patch
13
- ::FactoryGirl::FactoryRunner.prepend(FactoryGirlPatch) if
14
- defined?(::FactoryGirl)
13
+ TestProf.require 'factory_girl' do
14
+ ::FactoryGirl::FactoryRunner.prepend(FactoryGirlPatch)
15
+ end
15
16
  end
16
17
 
17
18
  def self.track(strategy, factory, &block)
@@ -9,6 +9,7 @@ module TestProf::FactoryProf
9
9
  include TestProf::Logging
10
10
 
11
11
  def dump(result)
12
+ return log(:info, "No factories detected") if result.raw_stats == {}
12
13
  report_data = {
13
14
  total_stacks: result.stacks.size,
14
15
  total: result.total
@@ -10,6 +10,7 @@ module TestProf::FactoryProf
10
10
  using TestProf::StringStripHeredoc
11
11
 
12
12
  def dump(result)
13
+ return log(:info, "No factories detected") if result.raw_stats == {}
13
14
  msgs = []
14
15
 
15
16
  msgs <<
@@ -5,6 +5,7 @@ module TestProf
5
5
  module Logging
6
6
  COLORS = {
7
7
  info: "\e[34m", # blue
8
+ warn: "\e[33m", # yellow
8
9
  error: "\e[31m", # red
9
10
  }.freeze
10
11
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof"
3
4
  require_relative "./before_all"
4
5
 
5
6
  module TestProf
@@ -13,6 +14,11 @@ module TestProf
13
14
  end
14
15
  end
15
16
 
17
+ # Only works with RSpec 3.2.0
18
+ def supported?
19
+ TestProf::Utils.verify_gem_version('rspec', at_least: '3.2.0')
20
+ end
21
+
16
22
  private
17
23
 
18
24
  def modules
@@ -25,6 +31,11 @@ module TestProf
25
31
  PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__".freeze : "@😸".freeze
26
32
 
27
33
  def let_it_be(identifier, **options, &block)
34
+ unless LetItBe.supported?
35
+ TestProf.log :warn, "let_it_be requires RSpec >= 3.2.0. Fallback to let!"
36
+ return let!(identifier, &block)
37
+ end
38
+
28
39
  initializer = proc do
29
40
  instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
30
41
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TestProf
4
4
  # Add ability to run only a specified number of example groups (randomly selected)
5
- module RspecSample
5
+ module RSpecSample
6
6
  def ordered_example_groups
7
7
  @example_groups = @example_groups.sample(ENV['SAMPLE'].to_i) unless ENV['SAMPLE'].nil?
8
8
  super
@@ -10,4 +10,4 @@ module TestProf
10
10
  end
11
11
  end
12
12
 
13
- RSpec::Core::World.prepend(TestProf::RspecSample)
13
+ RSpec::Core::World.prepend(TestProf::RSpecSample)
@@ -62,8 +62,11 @@ module TestProf
62
62
 
63
63
  def init
64
64
  RSpec::Core::Example.prepend(ExampleInstrumentation)
65
- RSpec::Core::MemoizedHelpers::ThreadsafeMemoized.prepend(MemoizedInstrumentation)
66
- RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized.prepend(MemoizedInstrumentation)
65
+
66
+ if memoization_available?
67
+ RSpec::Core::MemoizedHelpers::ThreadsafeMemoized.prepend(MemoizedInstrumentation)
68
+ RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized.prepend(MemoizedInstrumentation)
69
+ end
67
70
 
68
71
  @data = {}
69
72
 
@@ -92,6 +95,11 @@ module TestProf
92
95
  end
93
96
  end
94
97
 
98
+ # Whether we are able to track `let` usage
99
+ def memoization_available?
100
+ defined?(::RSpec::Core::MemoizedHelpers::ThreadsafeMemoized)
101
+ end
102
+
95
103
  METRICS.each do |type|
96
104
  define_method("#{type}_time") do
97
105
  @data[type.to_s]
@@ -7,6 +7,7 @@ require "test_prof/ext/string_strip_heredoc"
7
7
 
8
8
  module TestProf
9
9
  module RSpecDissect
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class Listener # :nodoc:
11
12
  include Logging
12
13
  using FloatDuration
@@ -16,6 +17,9 @@ module TestProf
16
17
  NOTIFICATIONS = %i[
17
18
  example_finished
18
19
  example_group_finished
20
+ example_passed
21
+ example_failed
22
+ example_pending
19
23
  ].freeze
20
24
 
21
25
  def initialize
@@ -35,6 +39,11 @@ module TestProf
35
39
  @examples_time += notification.example.execution_result.run_time
36
40
  end
37
41
 
42
+ # NOTE: RSpec < 3.4.0 doesn't have example_finished event
43
+ alias example_passed example_finished
44
+ alias example_failed example_finished
45
+ alias example_pending example_finished
46
+
38
47
  def example_group_finished(notification)
39
48
  return unless notification.group.top_level?
40
49
 
@@ -65,10 +74,15 @@ module TestProf
65
74
 
66
75
  Total time: #{@total_examples_time.duration}
67
76
  Total `before(:each)` time: #{RSpecDissect.total_before_time.duration}
68
- Total `let` time: #{RSpecDissect.total_memo_time.duration}
69
-
70
77
  MSG
71
78
 
79
+ msgs <<
80
+ if RSpecDissect.memoization_available?
81
+ "Total `let` time: #{RSpecDissect.total_memo_time.duration}\n\n"
82
+ else
83
+ "Total `let` time: NOT SUPPORTED (requires RSpec >= 3.3.0)\n\n"
84
+ end
85
+
72
86
  msgs <<
73
87
  <<-MSG.strip_heredoc
74
88
  Top #{top_count} slowest suites (by `before(:each)` time):
@@ -82,18 +96,20 @@ module TestProf
82
96
  GROUP
83
97
  end
84
98
 
85
- msgs <<
86
- <<-MSG.strip_heredoc
99
+ if RSpecDissect.memoization_available?
100
+ msgs <<
101
+ <<-MSG.strip_heredoc
87
102
 
88
- Top #{top_count} slowest suites (by `let` time):
103
+ Top #{top_count} slowest suites (by `let` time):
89
104
 
90
- MSG
105
+ MSG
91
106
 
92
- @memo_results.each do |group|
93
- msgs <<
94
- <<-GROUP.strip_heredoc
95
- #{group[:desc].truncate} (#{group[:loc]}) – #{group[:memo].duration} of #{group[:total].duration} (#{group[:count]})
96
- GROUP
107
+ @memo_results.each do |group|
108
+ msgs <<
109
+ <<-GROUP.strip_heredoc
110
+ #{group[:desc].truncate} (#{group[:loc]}) – #{group[:memo].duration} of #{group[:total].duration} (#{group[:count]})
111
+ GROUP
112
+ end
97
113
  end
98
114
 
99
115
  log :info, msgs.join
@@ -12,7 +12,8 @@ module TestProf
12
12
 
13
13
  NOTIFICATIONS = %i[
14
14
  example_started
15
- example_finished
15
+ example_failed
16
+ example_passed
16
17
  ].freeze
17
18
 
18
19
  def initialize
@@ -27,14 +28,16 @@ module TestProf
27
28
  end
28
29
 
29
30
  def example_finished(notification)
30
- return if notification.example.pending?
31
-
32
31
  tag = notification.example.metadata.fetch(@tag, :__unknown__)
33
32
 
34
33
  @tags[tag][:count] += 1
35
34
  @tags[tag][:time] += (TestProf.now - @ts)
36
35
  end
37
36
 
37
+ # NOTE: RSpec < 3.4.0 doesn't have example_finished event
38
+ alias example_passed example_finished
39
+ alias example_failed example_finished
40
+
38
41
  def print
39
42
  msgs = []
40
43
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.4.0".freeze
4
+ VERSION = "0.4.1".freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-03 00:00:00.000000000 Z
11
+ date: 2017-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,7 +83,7 @@ dependencies:
83
83
  description: "\n Ruby applications tests profiling tools.\n\n Contains tools
84
84
  to analyze factories usage, integrate with Ruby profilers,\n profile your examples
85
85
  using ActiveSupport notifications (if any) and\n statically analyze your code
86
- with custom Rubocop cops.\n "
86
+ with custom RuboCop cops.\n "
87
87
  email:
88
88
  - dementiev.vm@gmail.com
89
89
  executables: []
@@ -116,7 +116,10 @@ files:
116
116
  - guides/stack_prof.md
117
117
  - guides/tag_prof.md
118
118
  - guides/tests_sampling.md
119
- - lib/minitest/event_prof_plugin.rb
119
+ - lib/minitest/base_reporter.rb
120
+ - lib/minitest/event_prof_formatter.rb
121
+ - lib/minitest/fd_ignorable.rb
122
+ - lib/minitest/test_prof_plugin.rb
120
123
  - lib/test-prof.rb
121
124
  - lib/test_prof.rb
122
125
  - lib/test_prof/any_fixture.rb
@@ -126,7 +129,6 @@ files:
126
129
  - lib/test_prof/event_prof/custom_events/factory_create.rb
127
130
  - lib/test_prof/event_prof/custom_events/sidekiq_inline.rb
128
131
  - lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb
129
- - lib/test_prof/event_prof/formatters/minitest.rb
130
132
  - lib/test_prof/event_prof/instrumentations/active_support.rb
131
133
  - lib/test_prof/event_prof/minitest.rb
132
134
  - lib/test_prof/event_prof/rspec.rb
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_prof/event_prof/minitest'
4
-
5
- module Minitest # :nodoc:
6
- def self.plugin_event_prof_options(opts, options)
7
- opts.on "--event-prof=EVENT", "Collects metrics for specified EVENT" do |event|
8
- options[:event] = event
9
- end
10
- opts.on "--event-prof-rank-by=RANK_BY", "Defines RANK_BY parameter for results" do |rank|
11
- options[:rank_by] = rank.to_sym
12
- end
13
- opts.on "--event-prof-top-count=N", "Limits results with N groups/examples" do |count|
14
- options[:top_count] = count.to_i
15
- end
16
- opts.on "--event-prof-per-example", TrueClass, "Includes examples metrics to results" do |flag|
17
- options[:per_example] = flag
18
- end
19
- end
20
-
21
- def self.plugin_event_prof_init(options)
22
- options[:event] = ENV['EVENT_PROF'] if ENV['EVENT_PROF']
23
- options[:rank_by] = ENV['EVENT_PROF_RANK'].to_sym if ENV['EVENT_PROF_RANK']
24
- options[:top_count] = ENV['EVENT_PROF_TOP'].to_i if ENV['EVENT_PROF_TOP']
25
- options[:per_example] = true if ENV['EVENT_PROF_EXAMPLES']
26
-
27
- return unless options[:event]
28
- reporter << EventProfReporter.new(options[:io], options)
29
- end
30
- end