test-prof 0.4.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +106 -20
- data/README.md +10 -57
- data/assets/tagprof.demo.html +447 -0
- data/assets/tagprof.template.html +447 -0
- data/lib/minitest/event_prof_formatter.rb +18 -16
- data/lib/test_prof/any_fixture/dsl.rb +18 -0
- data/lib/test_prof/any_fixture.rb +92 -8
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -1
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +1 -1
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +1 -1
- data/lib/test_prof/event_prof/custom_events.rb +30 -0
- data/lib/test_prof/event_prof/minitest.rb +6 -0
- data/lib/test_prof/event_prof/profiler.rb +129 -0
- data/lib/test_prof/event_prof/rspec.rb +20 -11
- data/lib/test_prof/event_prof.rb +10 -108
- data/lib/test_prof/ext/active_record_refind.rb +20 -0
- data/lib/test_prof/factory_all_stub/factory_bot_patch.rb +13 -0
- data/lib/test_prof/factory_all_stub.rb +32 -0
- data/lib/test_prof/factory_doctor/rspec.rb +3 -2
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +9 -13
- data/lib/test_prof/recipes/active_record_one_love.rb +4 -0
- data/lib/test_prof/recipes/active_record_shared_connection.rb +55 -0
- data/lib/test_prof/recipes/logging.rb +37 -0
- data/lib/test_prof/recipes/rspec/any_fixture.rb +4 -1
- data/lib/test_prof/recipes/rspec/factory_all_stub.rb +10 -0
- data/lib/test_prof/rspec_dissect/rspec.rb +4 -2
- data/lib/test_prof/rspec_stamp/rspec.rb +3 -2
- data/lib/test_prof/tag_prof/printers/html.rb +24 -0
- data/lib/test_prof/tag_prof/printers/simple.rb +82 -0
- data/lib/test_prof/tag_prof/result.rb +38 -0
- data/lib/test_prof/tag_prof/rspec.rb +43 -40
- data/lib/test_prof/tag_prof.rb +4 -0
- data/lib/test_prof/utils/html_builder.rb +21 -0
- data/lib/test_prof/version.rb +1 -1
- data/lib/test_prof.rb +2 -1
- metadata +20 -22
- data/assets/logo.svg +0 -1
- data/assets/testprof.png +0 -0
- data/guides/.rubocop.yml +0 -1
- data/guides/any_fixture.md +0 -114
- data/guides/before_all.md +0 -98
- data/guides/event_prof.md +0 -177
- data/guides/factory_default.md +0 -111
- data/guides/factory_doctor.md +0 -119
- data/guides/factory_prof.md +0 -86
- data/guides/let_it_be.md +0 -97
- data/guides/rspec_dissect.md +0 -60
- data/guides/rspec_stamp.md +0 -52
- data/guides/rubocop.md +0 -48
- data/guides/ruby_prof.md +0 -63
- data/guides/stack_prof.md +0 -47
- data/guides/tag_prof.md +0 -51
- data/guides/tests_sampling.md +0 -24
data/guides/factory_doctor.md
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# Factory Doctor
|
|
2
|
-
|
|
3
|
-
One common bad pattern that slows our tests down is unnecessary database manipulation. Consider a _bad_ example:
|
|
4
|
-
|
|
5
|
-
```ruby
|
|
6
|
-
it 'validates name presence' do
|
|
7
|
-
user = create(:user)
|
|
8
|
-
user.name = ''
|
|
9
|
-
expect(user).not_to be_valid
|
|
10
|
-
end
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Here we create a new user record, run all callbacks and validations and save it to the database. We don't need all these! Here is a _good_ example:
|
|
14
|
-
|
|
15
|
-
```ruby
|
|
16
|
-
it 'validates name presence' do
|
|
17
|
-
user = build_stubbed(:user)
|
|
18
|
-
user.name = ''
|
|
19
|
-
expect(user).not_to be_valid
|
|
20
|
-
end
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Read more about [`build_stubbed`](https://robots.thoughtbot.com/use-factory-girls-build-stubbed-for-a-faster-test).
|
|
24
|
-
|
|
25
|
-
FactoryDoctor is a tool that helps you identify such _bad_ tests, i.e. tests that perform unnecessary database queries.
|
|
26
|
-
|
|
27
|
-
Example output:
|
|
28
|
-
|
|
29
|
-
```sh
|
|
30
|
-
[TEST PROF INFO] FactoryDoctor report
|
|
31
|
-
|
|
32
|
-
Total (potentially) bad examples: 2
|
|
33
|
-
Total wasted time: 00:13.165
|
|
34
|
-
|
|
35
|
-
User (./spec/models/user_spec.rb:3)
|
|
36
|
-
validates name (./spec/user_spec.rb:8) – 1 record created, 00:00.114
|
|
37
|
-
validates email (./spec/user_spec.rb:8) – 2 records created, 00:00.514
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**NOTE**: have you noticed the "potentially" word? Unfortunately, FactoryDoctor is not a
|
|
41
|
-
magician (it's still learning) and sometimes it produces false negatives and false positives too.
|
|
42
|
-
|
|
43
|
-
Please, submit an [issue](https://github.com/palkan/test-prof/issues) if you found a case which makes FactoryDoctor fail.
|
|
44
|
-
|
|
45
|
-
You can also tell FactoryDoctor to ignore specific examples/groups. Just add the `:fd_ignore` tag to it:
|
|
46
|
-
|
|
47
|
-
```ruby
|
|
48
|
-
# won't be reported as offense
|
|
49
|
-
it 'is ignored', :fd_ignore do
|
|
50
|
-
user = create(:user)
|
|
51
|
-
user.name = ''
|
|
52
|
-
expect(user).not_to be_valid
|
|
53
|
-
end
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Instructions
|
|
57
|
-
|
|
58
|
-
Currently, FactoryDoctor works only with FactoryGirl/FactoryBot.
|
|
59
|
-
|
|
60
|
-
## RSpec
|
|
61
|
-
|
|
62
|
-
To activate FactoryDoctor use `FDOC` environment variable:
|
|
63
|
-
|
|
64
|
-
```sh
|
|
65
|
-
FDOC=1 rspec ...
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Using with RSpecStamp
|
|
69
|
-
|
|
70
|
-
FactoryDoctor can be used with [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md) to automatically mark _bad_ examples with custom tags. For example:
|
|
71
|
-
|
|
72
|
-
```sh
|
|
73
|
-
FDOC=1 FDOC_STAMP="fdoc:consider" rspec ...
|
|
74
|
-
```
|
|
75
|
-
|
|
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.
|
data/guides/factory_prof.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# FactoryProf
|
|
2
|
-
|
|
3
|
-
FactoryProf tracks your factories usage statistics, i.e. how often each factory has been used.
|
|
4
|
-
|
|
5
|
-
Example output:
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
[TEST PROF INFO] Factories usage
|
|
9
|
-
|
|
10
|
-
total top-level name
|
|
11
|
-
|
|
12
|
-
8 4 user
|
|
13
|
-
5 3 post
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
**NOTE**: FactoryProf only tracks the database-persisted factories. In case of FactoryGirl/FactoryBot these are the factories
|
|
20
|
-
provided by using `create` strategy. In case of Fabrication - objects that created using `create` method.
|
|
21
|
-
|
|
22
|
-
## Instructions
|
|
23
|
-
|
|
24
|
-
FactoryProf can be used with FactoryGirl/FactoryBot or Fabrication - application can be bundled with both gems at the same time.
|
|
25
|
-
|
|
26
|
-
To activate FactoryProf use `FPROF` environment variable:
|
|
27
|
-
|
|
28
|
-
```sh
|
|
29
|
-
# Simple profiler
|
|
30
|
-
FPROF=1 rspec
|
|
31
|
-
|
|
32
|
-
# or
|
|
33
|
-
FPROF=1 bundle exec rake test
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Factory Flamegraph
|
|
37
|
-
|
|
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
|
-
|
|
40
|
-
To generate FactoryFlame report set `FPROF` environment variable to `flamegraph`:
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
FPROF=flamegraph rspec
|
|
44
|
-
|
|
45
|
-
# or
|
|
46
|
-
FPROF=flamegraph bundle exec rake test
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
That's how a report looks like:
|
|
50
|
-
|
|
51
|
-

|
|
52
|
-
|
|
53
|
-
How to read this?
|
|
54
|
-
|
|
55
|
-
Every column represents a _factory stack_ or _cascade_, that is a sequence of recursive `#create` method calls. Consider an example:
|
|
56
|
-
|
|
57
|
-
```ruby
|
|
58
|
-
factory :comment do
|
|
59
|
-
answer
|
|
60
|
-
author
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
factory :answer do
|
|
64
|
-
question
|
|
65
|
-
author
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
factory :question do
|
|
69
|
-
author
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
create(:comment) #=> creates 5 records
|
|
73
|
-
|
|
74
|
-
# And the corresponding stack is:
|
|
75
|
-
# [:comment, :answer, :question, :author, :author, :author]
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
The wider column the more often this stack appears.
|
|
79
|
-
|
|
80
|
-
The `root` cell shows the total number of `create` calls.
|
|
81
|
-
|
|
82
|
-
## Acknowledgements
|
|
83
|
-
|
|
84
|
-
- Thanks to [Martin Spier](https://github.com/spiermar) for [d3-flame-graph](https://github.com/spiermar/d3-flame-graph)
|
|
85
|
-
|
|
86
|
-
- Thanks to [Sam Saffron](https://github.com/SamSaffron) for his [flame graphs implementation](https://github.com/SamSaffron/flamegraph).
|
data/guides/let_it_be.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Let It Be!
|
|
2
|
-
|
|
3
|
-
Let's bring a little bit of magic and introduce a new way to setup a _shared_ test data.
|
|
4
|
-
|
|
5
|
-
Suppose you have the following setup:
|
|
6
|
-
|
|
7
|
-
```ruby
|
|
8
|
-
describe BeatleWeightedSearchQuery do
|
|
9
|
-
let!(:paul) { create(:beatle, name: 'Paul') }
|
|
10
|
-
let!(:ringo) { create(:beatle, name: 'Ringo') }
|
|
11
|
-
let!(:george) { create(:beatle, name: 'George') }
|
|
12
|
-
let!(:john) { create(:beatle, name: 'John') }
|
|
13
|
-
|
|
14
|
-
specify { expect(subject.call('john')).to contain_exactly(john) }
|
|
15
|
-
|
|
16
|
-
# and more examples here
|
|
17
|
-
end
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
We don't need to re-create the Fab Four for every example, do we?
|
|
21
|
-
|
|
22
|
-
We already have [`before_all`](https://github.com/palkan/test-prof/tree/master/guides/before_all.md) to solve the problem of _repeatable_ data:
|
|
23
|
-
|
|
24
|
-
```ruby
|
|
25
|
-
describe BeatleWeightedSearchQuery do
|
|
26
|
-
before_all do
|
|
27
|
-
@paul = create(:beatle, name: 'Paul')
|
|
28
|
-
# ...
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
specify { expect(subject.call('joh')).to contain_exactly(@john) }
|
|
32
|
-
|
|
33
|
-
# ...
|
|
34
|
-
end
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
That technique works pretty good but requires us to use instance variables and define everything at once. Thus it's not easy to refactor existing tests which use `let/let!` instead.
|
|
38
|
-
|
|
39
|
-
With `let_it_be` you can do the following:
|
|
40
|
-
|
|
41
|
-
```ruby
|
|
42
|
-
describe BeatleWeightedSearchQuery do
|
|
43
|
-
let_it_be(:paul) { create(:beatle, name: 'Paul') }
|
|
44
|
-
let_it_be(:ringo) { create(:beatle, name: 'Ringo') }
|
|
45
|
-
let_it_be(:george) { create(:beatle, name: 'George') }
|
|
46
|
-
let_it_be(:john) { create(:beatle, name: 'John') }
|
|
47
|
-
|
|
48
|
-
specify { expect(subject.call('john')).to contain_exactly(john) }
|
|
49
|
-
|
|
50
|
-
# and more examples here
|
|
51
|
-
end
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
That's it! Just replace `let!` with `let_it_be`. That's equal to the `before_all` approach but requires less refactoring.
|
|
55
|
-
|
|
56
|
-
**NOTE**: requires RSpec >= 3.2.0.
|
|
57
|
-
|
|
58
|
-
## Instructions
|
|
59
|
-
|
|
60
|
-
In your `spec_helper.rb`:
|
|
61
|
-
|
|
62
|
-
```ruby
|
|
63
|
-
require 'test_prof/recipes/rspec/let_it_be'
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
In your tests:
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
describe MySuperDryService do
|
|
70
|
-
let_it_be(:user) { create(:user) }
|
|
71
|
-
|
|
72
|
-
# ...
|
|
73
|
-
end
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Caveats
|
|
77
|
-
|
|
78
|
-
If you modify objects generated within a `let_it_be` block in your examples, you maybe have to re-initiate them.
|
|
79
|
-
We have a built-in support for that:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```ruby
|
|
83
|
-
# Use reload: true option to reload user object (assuming it's an instance of ActiveRecord)
|
|
84
|
-
# for every example
|
|
85
|
-
let_it_be(:user, reload: true) { create(:user) }
|
|
86
|
-
|
|
87
|
-
# it is almost equal to
|
|
88
|
-
before_all { @user = create(:user) }
|
|
89
|
-
let(:user) { @user.reload }
|
|
90
|
-
|
|
91
|
-
# You can also specify refind: true option to hard-reload the record
|
|
92
|
-
let_it_be(:user, refind: true) { create(:user) }
|
|
93
|
-
|
|
94
|
-
# it is almost equal to
|
|
95
|
-
before_all { @user = create(:user) }
|
|
96
|
-
let(:user) { User.find(@user.id) }
|
|
97
|
-
```
|
data/guides/rspec_dissect.md
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# RSpecDissect
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
Example output:
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
[TEST PROF INFO] RSpecDissect enabled
|
|
11
|
-
|
|
12
|
-
Total time: 25:14.870
|
|
13
|
-
Total `before(:each)` time: 14:36.482
|
|
14
|
-
Total `let` time: 19:20.259
|
|
15
|
-
|
|
16
|
-
Top 5 slowest suites (by `before(:each)` time):
|
|
17
|
-
|
|
18
|
-
Webhooks::DispatchTransition (./spec/services/webhooks/dispatch_transition_spec.rb:3) – 00:29.895 of 00:33.706 (327)
|
|
19
|
-
FunnelsController (./spec/controllers/funnels_controller_spec.rb:3) – 00:22.117 of 00:43.649 (133)
|
|
20
|
-
ApplicantsController (./spec/controllers/applicants_controller_spec.rb:3) – 00:21.220 of 00:41.407 (222)
|
|
21
|
-
BookedSlotsController (./spec/controllers/booked_slots_controller_spec.rb:3) – 00:15.729 of 00:27.893 (50)
|
|
22
|
-
Analytics::Wor...rsion::Summary (./spec/services/analytics/workflow_conversion/summary_spec.rb:3) – 00:15.383 of 00:15.914 (12)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Top 5 slowest suites (by `let` time):
|
|
26
|
-
|
|
27
|
-
FunnelsController (./spec/controllers/funnels_controller_spec.rb:3) – 00:38.532 of 00:43.649 (133)
|
|
28
|
-
ApplicantsController (./spec/controllers/applicants_controller_spec.rb:3) – 00:33.252 of 00:41.407 (222)
|
|
29
|
-
Webhooks::DispatchTransition (./spec/services/webhooks/dispatch_transition_spec.rb:3) – 00:30.320 of 00:33.706 (327)
|
|
30
|
-
BookedSlotsController (./spec/controllers/booked_slots_controller_spec.rb:3) – 00:25.710 of 00:27.893 (50)
|
|
31
|
-
AvailableSlotsController (./spec/controllers/available_slots_controller_spec.rb:3) – 00:18.481 of 00:23.366 (85)
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**NOTE**: Tracking `let` time only supported in RSpec >= 3.3.0.
|
|
35
|
-
|
|
36
|
-
## Instructions
|
|
37
|
-
|
|
38
|
-
RSpecDissect can only be used with RSpec (which is clear from the name).
|
|
39
|
-
|
|
40
|
-
To activate RSpecDissect use `RD_PROF` environment variable:
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
RD_PROF=1 rspec ...
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
You can also specify the number of top slow groups through `RD_PROF_TOP` variable:
|
|
47
|
-
|
|
48
|
-
```sh
|
|
49
|
-
RD_PROF=1 RD_PROF_TOP=10 rspec ...
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Using with RSpecStamp
|
|
53
|
-
|
|
54
|
-
RSpecDissect can be used with [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md) to automatically mark _slow_ examples with custom tags. For example:
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
RD_PROF=1 RD_PROF_STAMP="slow" rspec ...
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
After running the command above the slowest example groups would be marked with the `:slow` tag.
|
data/guides/rspec_stamp.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# RSpecStamp
|
|
2
|
-
|
|
3
|
-
RSpecStamp is a tool to automatically _tag_ failed examples with custom tags.
|
|
4
|
-
|
|
5
|
-
It _literally_ adds tags to your examples (i.e. rewrites them).
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
## Example Use Case: Sidekiq Inline
|
|
10
|
-
|
|
11
|
-
Using `Sidekiq::Testing.inline!` may be considered a _bad practice_ (see [here](https://github.com/mperham/sidekiq/issues/3495)) due to its negative performance impact. But it's still widely used.
|
|
12
|
-
|
|
13
|
-
How to migrate from `inline!` to `fake!`?
|
|
14
|
-
|
|
15
|
-
Step 0. Make sure that all your tests pass.
|
|
16
|
-
|
|
17
|
-
Step 1. Create a shared context to conditionally turn on `inline!` mode:
|
|
18
|
-
|
|
19
|
-
```ruby
|
|
20
|
-
shared_context 'sidekiq:inline', sidekiq: :inline do
|
|
21
|
-
around(:each) { |ex| Sidekiq::Testing.inline!(&ex) }
|
|
22
|
-
end
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Step 2. Turn on `fake!` mode globally.
|
|
26
|
-
|
|
27
|
-
Step 3. Run `RSTAMP=sidekiq:inline rspec`.
|
|
28
|
-
|
|
29
|
-
The output of the command above contains information about the _stamping_ process:
|
|
30
|
-
|
|
31
|
-
- How many files have been affected?
|
|
32
|
-
|
|
33
|
-
- How many patches were made?
|
|
34
|
-
|
|
35
|
-
- How many patches failed?
|
|
36
|
-
|
|
37
|
-
- How many files have been ignored?
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
43
|
-
## Configuration
|
|
44
|
-
|
|
45
|
-
By default, RSpecStamp ignores examples located in `spec/support` directory (typical place to put shared examples in).
|
|
46
|
-
You can add more _ignore_ patterns:
|
|
47
|
-
|
|
48
|
-
```ruby
|
|
49
|
-
TestProf::RSpecStamp.configure do |config|
|
|
50
|
-
config.ignore_files << %r{spec/my_directory}
|
|
51
|
-
end
|
|
52
|
-
```
|
data/guides/rubocop.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Custom RuboCop Cops
|
|
2
|
-
|
|
3
|
-
TestProf comes with the [RuboCop](https://github.com/bbatsov/rubocop) cops that help you write more performant tests.
|
|
4
|
-
|
|
5
|
-
To enable them:
|
|
6
|
-
|
|
7
|
-
- Require `test_prof/rubocop` in your RuboCop configuration:
|
|
8
|
-
|
|
9
|
-
```yml
|
|
10
|
-
# .rubocop.yml
|
|
11
|
-
require:
|
|
12
|
-
- 'test_prof/rubocop'
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
- Enable cops:
|
|
16
|
-
|
|
17
|
-
```yml
|
|
18
|
-
RSpec/AggregateFailures:
|
|
19
|
-
Enabled: true
|
|
20
|
-
Include:
|
|
21
|
-
- 'spec/**/*.rb'
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## RSpec/AggregateFailures
|
|
25
|
-
|
|
26
|
-
This cop encourages you to use one of the greatest features of the recent RSpec – aggregating failures within an example.
|
|
27
|
-
|
|
28
|
-
Instead of writing one example per assertion, you can group _independent_ assertions together, thus running all setup hooks only once. That can dramatically increase your performance (by reducing the total number of examples).
|
|
29
|
-
|
|
30
|
-
Consider an example:
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# bad
|
|
34
|
-
it { is_expected.to be_success }
|
|
35
|
-
it { is_expected.to have_header('X-TOTAL-PAGES', 10) }
|
|
36
|
-
it { is_expected.to have_header('X-NEXT-PAGE', 2) }
|
|
37
|
-
|
|
38
|
-
# good
|
|
39
|
-
it 'returns the second page', :aggregate_failures do
|
|
40
|
-
is_expected.to be_success
|
|
41
|
-
is_expected.to have_header('X-TOTAL-PAGES', 10)
|
|
42
|
-
is_expected.to have_header('X-NEXT-PAGE', 2)
|
|
43
|
-
end
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
This cop supports auto-correct feature, so you can automatically refactor you legacy tests!
|
|
47
|
-
|
|
48
|
-
**NOTE**: auto-correction may break your tests (especially the ones using block-matchers, such as `change`).
|
data/guides/ruby_prof.md
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Profiling with RubyProf
|
|
2
|
-
|
|
3
|
-
Easily integrate the power of [ruby-prof](https://github.com/ruby-prof/ruby-prof) into your test suite.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
Install `ruby-prof` gem (>= 0.16):
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
# Gemfile
|
|
11
|
-
group :development, :test do
|
|
12
|
-
gem 'ruby-prof', '>= 0.16.0', require: false
|
|
13
|
-
end
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
RubyProf profiler has two modes: `global` and `per-example`.
|
|
17
|
-
|
|
18
|
-
You can activate the global profiling using the environment variable `TEST_RUBY_PROF`:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
TEST_RUBY_PROF=1 bundle exec rake test
|
|
22
|
-
|
|
23
|
-
# or for RSpec
|
|
24
|
-
TEST_RUBY_PROF=1 rspec ...
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Or in your code:
|
|
28
|
-
|
|
29
|
-
```ruby
|
|
30
|
-
TestProf::RubyProf.run
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
TestProf provides a built-in shared context for RSpec to profile examples individually:
|
|
34
|
-
|
|
35
|
-
```ruby
|
|
36
|
-
it 'is doing heavy stuff', :rprof do
|
|
37
|
-
# ...
|
|
38
|
-
end
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Configuration
|
|
42
|
-
|
|
43
|
-
The most useful configuration option is `printer` – it allows you to specify a RubyProf [printer](https://github.com/ruby-prof/ruby-prof#printers).
|
|
44
|
-
|
|
45
|
-
You can specify a printer through environment variable `TEST_RUBY_PROF`:
|
|
46
|
-
|
|
47
|
-
```sh
|
|
48
|
-
TEST_RUBY_PROF=call_stack bundle exec rake test
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Or in your code:
|
|
52
|
-
|
|
53
|
-
```ruby
|
|
54
|
-
TestProf::RubyProf.configure do |config|
|
|
55
|
-
config.printer = :call_stack
|
|
56
|
-
end
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
By default, we use `FlatPrinter`.
|
|
60
|
-
|
|
61
|
-
Also, you can specify RubyProf mode (`wall`, `cpu`, etc) through `TEST_RUBY_PROF_MODE` env variable.
|
|
62
|
-
|
|
63
|
-
See [ruby_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/ruby_prof.rb) for all available configuration options and their usage.
|
data/guides/stack_prof.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Profiling with StackProf
|
|
2
|
-
|
|
3
|
-
[StackProf](https://github.com/tmm1/stackprof) is a sampling call-stack profiler for ruby.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
Install `stackprof` gem (>= 0.2.9):
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
# Gemfile
|
|
11
|
-
group :development, :test do
|
|
12
|
-
gem 'stackprof', '>= 0.2.9', require: false
|
|
13
|
-
end
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
StackProf profiler has 2 modes: `global` and `per-example`.
|
|
17
|
-
|
|
18
|
-
You can activate global profiling using the environment variable `TEST_STACK_PROF`:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
TEST_STACK_PROF=1 bundle exec rake test
|
|
22
|
-
|
|
23
|
-
# or for RSpec
|
|
24
|
-
TEST_STACK_PROF=1 rspec ...
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Or in your code:
|
|
28
|
-
|
|
29
|
-
```ruby
|
|
30
|
-
TestProf::StackProf.run
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
TestProf provides a built-in shared context for RSpec to profile examples individually:
|
|
34
|
-
|
|
35
|
-
```ruby
|
|
36
|
-
it 'is doing heavy stuff', :sprof do
|
|
37
|
-
# ...
|
|
38
|
-
end
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Configuration
|
|
42
|
-
|
|
43
|
-
You can change StackProf mode (which is `wall` by default) through `TEST_STACK_PROF_MODE` env variable.
|
|
44
|
-
|
|
45
|
-
If you want to generate flame graphs you should collect _raw_ data. Turn _raw_ collection on by passing `TEST_STACK_PROF=raw`.
|
|
46
|
-
|
|
47
|
-
See [stack_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/stack_prof.rb) for all available configuration options and their usage.
|
data/guides/tag_prof.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# TagProf
|
|
2
|
-
|
|
3
|
-
TagProf is a simple profiler which collects examples statistics grouped by a provided tag value.
|
|
4
|
-
|
|
5
|
-
That's pretty useful in conjunction with `rspec-rails` built-in feature – `infer_spec_types_from_location!` – which automatically adds `type` to examples metadata.
|
|
6
|
-
|
|
7
|
-
Example output:
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
[TEST PROF INFO] TagProf report for type
|
|
11
|
-
|
|
12
|
-
type time total %total %time avg
|
|
13
|
-
|
|
14
|
-
request 00:04.808 42 33.87 54.70 00:00.114
|
|
15
|
-
controller 00:02.855 42 33.87 32.48 00:00.067
|
|
16
|
-
model 00:01.127 40 32.26 12.82 00:00.028
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
It shows both the total number of examples in each group and the total time spent (as long as percentages and average values).
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Instructions
|
|
24
|
-
|
|
25
|
-
TagProf can only be used with RSpec.
|
|
26
|
-
|
|
27
|
-
To activate TagProf use `TAG_PROF` environment variable:
|
|
28
|
-
|
|
29
|
-
```sh
|
|
30
|
-
# Group by type
|
|
31
|
-
TAG_PROF=type rspec
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Pro-Tip: More Types
|
|
35
|
-
|
|
36
|
-
By default, RSpec only infers types for default Rails app entities (such as controllers, models, mailers, etc.).
|
|
37
|
-
Modern Rails applications typically contain other abstractions too (e.g. services, forms, presenters, etc.), but RSpec is not aware of them and doesn't add any metadata.
|
|
38
|
-
|
|
39
|
-
That's the quick workaround:
|
|
40
|
-
|
|
41
|
-
```ruby
|
|
42
|
-
RSpec.configure do |config|
|
|
43
|
-
# ...
|
|
44
|
-
config.define_derived_metadata(file_path: %r{/spec/}) do |metadata|
|
|
45
|
-
# do not overwrite type if it's already set
|
|
46
|
-
next if metadata.key?(:type)
|
|
47
|
-
match = metadata[:location].match(%r{/spec/([^/]+)/})
|
|
48
|
-
metadata[:type] = match[1].singularize.to_sym
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
```
|
data/guides/tests_sampling.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Tests Sampling
|
|
2
|
-
|
|
3
|
-
Sometimes it's useful to run profilers against randomly chosen tests. Unfortunetaly, test frameworks don's support such functionality. That's why we've included small patches for RSpec and Minitest in TestProf.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## Instructions
|
|
7
|
-
|
|
8
|
-
Require the corresponding patch:
|
|
9
|
-
|
|
10
|
-
```ruby
|
|
11
|
-
# For RSpec in your spec_helper.rb
|
|
12
|
-
require 'test_prof/recipes/rspec/sample'
|
|
13
|
-
|
|
14
|
-
# For Minitest in your test_helper.rb
|
|
15
|
-
require 'test_prof/recipes/minitest/sample'
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
And then just add `SAMPLE` env variable with the number of example groups (or suites) you want to run:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
SAMPLE=10 rspec
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
That's it. Enjoy!
|