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
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
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vladimir Dementyev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-05-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -72,14 +72,14 @@ dependencies:
|
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 0.56.0
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: 0.56.0
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: rubocop-md
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -109,7 +109,6 @@ files:
|
|
|
109
109
|
- README.md
|
|
110
110
|
- assets/flamegraph.demo.html
|
|
111
111
|
- assets/flamegraph.template.html
|
|
112
|
-
- assets/logo.svg
|
|
113
112
|
- assets/src/d3-tip.js
|
|
114
113
|
- assets/src/d3-tip.min.js
|
|
115
114
|
- assets/src/d3.flameGraph.css
|
|
@@ -117,28 +116,15 @@ files:
|
|
|
117
116
|
- assets/src/d3.flameGraph.min.css
|
|
118
117
|
- assets/src/d3.flameGraph.min.js
|
|
119
118
|
- assets/src/d3.v4.min.js
|
|
120
|
-
- assets/
|
|
121
|
-
-
|
|
122
|
-
- guides/any_fixture.md
|
|
123
|
-
- guides/before_all.md
|
|
124
|
-
- guides/event_prof.md
|
|
125
|
-
- guides/factory_default.md
|
|
126
|
-
- guides/factory_doctor.md
|
|
127
|
-
- guides/factory_prof.md
|
|
128
|
-
- guides/let_it_be.md
|
|
129
|
-
- guides/rspec_dissect.md
|
|
130
|
-
- guides/rspec_stamp.md
|
|
131
|
-
- guides/rubocop.md
|
|
132
|
-
- guides/ruby_prof.md
|
|
133
|
-
- guides/stack_prof.md
|
|
134
|
-
- guides/tag_prof.md
|
|
135
|
-
- guides/tests_sampling.md
|
|
119
|
+
- assets/tagprof.demo.html
|
|
120
|
+
- assets/tagprof.template.html
|
|
136
121
|
- lib/minitest/base_reporter.rb
|
|
137
122
|
- lib/minitest/event_prof_formatter.rb
|
|
138
123
|
- lib/minitest/test_prof_plugin.rb
|
|
139
124
|
- lib/test-prof.rb
|
|
140
125
|
- lib/test_prof.rb
|
|
141
126
|
- lib/test_prof/any_fixture.rb
|
|
127
|
+
- lib/test_prof/any_fixture/dsl.rb
|
|
142
128
|
- lib/test_prof/cops/rspec/aggregate_failures.rb
|
|
143
129
|
- lib/test_prof/event_prof.rb
|
|
144
130
|
- lib/test_prof/event_prof/custom_events.rb
|
|
@@ -147,12 +133,16 @@ files:
|
|
|
147
133
|
- lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb
|
|
148
134
|
- lib/test_prof/event_prof/instrumentations/active_support.rb
|
|
149
135
|
- lib/test_prof/event_prof/minitest.rb
|
|
136
|
+
- lib/test_prof/event_prof/profiler.rb
|
|
150
137
|
- lib/test_prof/event_prof/rspec.rb
|
|
151
138
|
- lib/test_prof/ext/active_record_3.rb
|
|
139
|
+
- lib/test_prof/ext/active_record_refind.rb
|
|
152
140
|
- lib/test_prof/ext/array_bsearch_index.rb
|
|
153
141
|
- lib/test_prof/ext/float_duration.rb
|
|
154
142
|
- lib/test_prof/ext/string_strip_heredoc.rb
|
|
155
143
|
- lib/test_prof/ext/string_truncate.rb
|
|
144
|
+
- lib/test_prof/factory_all_stub.rb
|
|
145
|
+
- lib/test_prof/factory_all_stub/factory_bot_patch.rb
|
|
156
146
|
- lib/test_prof/factory_bot.rb
|
|
157
147
|
- lib/test_prof/factory_default.rb
|
|
158
148
|
- lib/test_prof/factory_default/factory_bot_patch.rb
|
|
@@ -168,9 +158,13 @@ files:
|
|
|
168
158
|
- lib/test_prof/factory_prof/printers/flamegraph.rb
|
|
169
159
|
- lib/test_prof/factory_prof/printers/simple.rb
|
|
170
160
|
- lib/test_prof/logging.rb
|
|
161
|
+
- lib/test_prof/recipes/active_record_one_love.rb
|
|
162
|
+
- lib/test_prof/recipes/active_record_shared_connection.rb
|
|
163
|
+
- lib/test_prof/recipes/logging.rb
|
|
171
164
|
- lib/test_prof/recipes/minitest/sample.rb
|
|
172
165
|
- lib/test_prof/recipes/rspec/any_fixture.rb
|
|
173
166
|
- lib/test_prof/recipes/rspec/before_all.rb
|
|
167
|
+
- lib/test_prof/recipes/rspec/factory_all_stub.rb
|
|
174
168
|
- lib/test_prof/recipes/rspec/factory_default.rb
|
|
175
169
|
- lib/test_prof/recipes/rspec/let_it_be.rb
|
|
176
170
|
- lib/test_prof/recipes/rspec/sample.rb
|
|
@@ -185,8 +179,12 @@ files:
|
|
|
185
179
|
- lib/test_prof/stack_prof.rb
|
|
186
180
|
- lib/test_prof/stack_prof/rspec.rb
|
|
187
181
|
- lib/test_prof/tag_prof.rb
|
|
182
|
+
- lib/test_prof/tag_prof/printers/html.rb
|
|
183
|
+
- lib/test_prof/tag_prof/printers/simple.rb
|
|
184
|
+
- lib/test_prof/tag_prof/result.rb
|
|
188
185
|
- lib/test_prof/tag_prof/rspec.rb
|
|
189
186
|
- lib/test_prof/utils.rb
|
|
187
|
+
- lib/test_prof/utils/html_builder.rb
|
|
190
188
|
- lib/test_prof/utils/sized_ordered_set.rb
|
|
191
189
|
- lib/test_prof/version.rb
|
|
192
190
|
homepage: http://github.com/palkan/test-prof
|
|
@@ -209,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
209
207
|
version: '0'
|
|
210
208
|
requirements: []
|
|
211
209
|
rubyforge_project:
|
|
212
|
-
rubygems_version: 2.7.
|
|
210
|
+
rubygems_version: 2.7.6
|
|
213
211
|
signing_key:
|
|
214
212
|
specification_version: 4
|
|
215
213
|
summary: Ruby applications tests profiling tools
|
data/assets/logo.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 86 100"><defs><linearGradient id="a" x1="43" y1="100" x2="43" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b5afbf"/><stop offset="1" stop-color="#dbd1d6"/></linearGradient><linearGradient id="b" x1="16" y1="87" x2="16" y2="73" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a99ea7"/><stop offset=".6" stop-color="#c8b8c1"/></linearGradient><linearGradient id="c" x1="14" y1="75" x2="14" y2="79" xlink:href="#linear-gradient-2"/><linearGradient id="d" x1="34" x2="34" xlink:href="#linear-gradient-2"/><linearGradient id="e" x1="36" y1="79" x2="36" y2="83" xlink:href="#linear-gradient-2"/></defs><rect fill="url(#a)" width="86" height="100" rx="13" ry="13"/><rect fill="#fef7f9" x="1" y="1" width="84" height="94" rx="12" ry="12"/><path fill="#fff" d="M73 1H13A12 12 0 0 0 1 13v1A12 12 0 0 1 13 2h60a12 12 0 0 1 12 12v-1A12 12 0 0 0 73 1z"/><rect fill="#7e628f" x="9" y="9" width="68" height="58" rx="4" ry="4"/><path fill="#675077" d="M73 9H13a4 4 0 0 0-4 4v1a4 4 0 0 1 4-4h60a4 4 0 0 1 4 4v-1a4 4 0 0 0-4-4z"/><rect fill="#d84b9d" x="51" y="73" width="26" height="14" rx="4" ry="4"/><rect fill="#f159b0" x="51" y="73" width="26" height="12" rx="4" ry="4"/><path fill="#fc7acb" d="M73 84H55a4 4 0 0 1-4-4v1a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4v-1a4 4 0 0 1-4 4z"/><circle fill="url(#b)" cx="16" cy="80" r="7"/><circle fill="#dec7d4" cx="16" cy="79" r="6"/><path fill="#f9edf4" d="M16 74a6 6 0 0 1 6 5.5V79a6 6 0 0 0-12 0v.5a6 6 0 0 1 6-5.5z"/><circle fill="url(#c)" cx="14" cy="77" r="2"/><circle fill="url(#d)" cx="34" cy="80" r="7"/><circle fill="#dec7d4" cx="34" cy="79" r="6"/><path fill="#f9edf4" d="M34 74a6 6 0 0 1 6 5.5V79a6 6 0 0 0-12 0v.5a6 6 0 0 1 6-5.5z"/><circle fill="url(#e)" cx="36" cy="81" r="2"/><path fill="#9072a0" d="M27 60.8A11.8 11.8 0 1 1 38.8 49 11.8 11.8 0 0 1 27 60.8zm0-20a8.2 8.2 0 1 0 8.2 8.2 8.2 8.2 0 0 0-8.2-8.2z"/><path fill="#fe5bb7" d="M37 51a2 2 0 0 1-2-2 8 8 0 0 0-8-8 2 2 0 0 1 0-4 12 12 0 0 1 12 12 2 2 0 0 1-2 2z"/><path fill="#9072a0" d="M59 60.8A11.8 11.8 0 1 1 70.8 49 11.8 11.8 0 0 1 59 60.8zm0-20a8.2 8.2 0 1 0 8.2 8.2 8.2 8.2 0 0 0-8.2-8.2z"/><path fill="#5bd3e8" d="M59 61a12 12 0 0 1-12-12 2 2 0 0 1 4 0 8 8 0 1 0 8-8 2 2 0 0 1 0-4 12 12 0 0 1 0 24z"/><path fill="#ffae43" d="M70 17.5l-11 11-4-5-7.8 8.8-11-21.2L26 25.7l-4-4-8 10.7-5-8V28l5 7.8 8-11.3 4 4L36 15l10.8 20.8 8.2-9.2 4 5 11-11 7 8.5v-3l-7-8.4z"/></svg>
|
data/assets/testprof.png
DELETED
|
Binary file
|
data/guides/.rubocop.yml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Leave it blank to use default Rubocop config in guides
|
data/guides/any_fixture.md
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# Any Fixture
|
|
2
|
-
|
|
3
|
-
Fixtures are the great way to increase your test suite performance, but for the large project, they are very hard to maintain.
|
|
4
|
-
|
|
5
|
-
We propose a more general approach to lazy-generate the _global_ state for your test suite – AnyFixture.
|
|
6
|
-
|
|
7
|
-
With AnyFixture you can use any block of code for data generation, and it will take care of cleaning it out at the end of the run.
|
|
8
|
-
|
|
9
|
-
Consider an example:
|
|
10
|
-
|
|
11
|
-
```ruby
|
|
12
|
-
# The best way to use AnyFixture is through RSpec shared contexts
|
|
13
|
-
RSpec.shared_context 'account', account: true do
|
|
14
|
-
# You should call AnyFixture outside of transaction to re-use the same
|
|
15
|
-
# data between examples
|
|
16
|
-
before(:all) do
|
|
17
|
-
# The provided name ("account") should be unique.
|
|
18
|
-
@account = TestProf::AnyFixture.register(:account) do
|
|
19
|
-
# Do anything here, AnyFixture keeps track of affected DB tables
|
|
20
|
-
# For example, you can use factories here
|
|
21
|
-
FactoryGirl.create(:account)
|
|
22
|
-
|
|
23
|
-
# or with Fabrication
|
|
24
|
-
Fabricate(:account)
|
|
25
|
-
|
|
26
|
-
# or with plain old AR
|
|
27
|
-
Account.create!(name: 'test')
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
let(:account) { @account }
|
|
32
|
-
|
|
33
|
-
# Or hard-reload object if there is chance of in-place modification
|
|
34
|
-
let(:account) { Account.find(@account.id) }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Then in your tests
|
|
38
|
-
|
|
39
|
-
# Active this fixture using a tag
|
|
40
|
-
describe UsersController, :account do
|
|
41
|
-
# ...
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# This test also uses the same account record,
|
|
45
|
-
# no double-creation
|
|
46
|
-
describe PostsController, :account do
|
|
47
|
-
# ...
|
|
48
|
-
end
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Instructions
|
|
52
|
-
|
|
53
|
-
In your `spec_helper.rb`:
|
|
54
|
-
|
|
55
|
-
```ruby
|
|
56
|
-
require 'test_prof/recipes/rspec/any_fixture'
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Now you can use `TestProf::AnyFixture` in your tests.
|
|
60
|
-
|
|
61
|
-
## Caveats
|
|
62
|
-
|
|
63
|
-
`AnyFixture` cleans tables in the reverse order as compared to the order they were populated. That
|
|
64
|
-
means when you register a fixture which references a not-yet-registered table, a
|
|
65
|
-
foreign-key violation error *might* occur (if any). An example is worth more than 1000
|
|
66
|
-
words:
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
class Author < ApplicationRecord
|
|
70
|
-
has_many :articles
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
class Article < ApplicationRecord
|
|
74
|
-
belongs_to :author
|
|
75
|
-
end
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
And the shared contexts:
|
|
79
|
-
|
|
80
|
-
```ruby
|
|
81
|
-
RSpec.shared_context 'author' do
|
|
82
|
-
before(:all) do
|
|
83
|
-
@author = TestProf::AnyFixture.register(:author) do
|
|
84
|
-
FactoryGirl.create(:account)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
let(:author) { @author }
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
RSpec.shared_context 'article' do
|
|
92
|
-
before(:all) do
|
|
93
|
-
# outside of AnyFixture, we don't know about its dependent tables
|
|
94
|
-
author = FactoryGirl.create(:author)
|
|
95
|
-
|
|
96
|
-
@article = TestProf::AnyFixture.register(:article) do
|
|
97
|
-
FactoryGirl.create(:article, author: author)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
let(:article) { @article }
|
|
102
|
-
end
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Then in some example:
|
|
106
|
-
|
|
107
|
-
```ruby
|
|
108
|
-
# This one adds only the 'articles' table to the list of affected tables
|
|
109
|
-
include_context 'article'
|
|
110
|
-
# And this one adds the 'authors' table
|
|
111
|
-
include_context 'author'
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
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.
|
data/guides/before_all.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Before All
|
|
2
|
-
|
|
3
|
-
Rails has a great feature – `transactional_tests`, i.e. running each example within a transaction which is roll-backed in the end.
|
|
4
|
-
|
|
5
|
-
Thus no example polutes global database state.
|
|
6
|
-
|
|
7
|
-
But what if have a lot of examples with a common setup?
|
|
8
|
-
|
|
9
|
-
Of course, we can do something like this:
|
|
10
|
-
|
|
11
|
-
```ruby
|
|
12
|
-
describe BeatleWeightedSearchQuery do
|
|
13
|
-
before(:each) do
|
|
14
|
-
@paul = create(:beatle, name: 'Paul')
|
|
15
|
-
@ringo = create(:beatle, name: 'Ringo')
|
|
16
|
-
@george = create(:beatle, name: 'George')
|
|
17
|
-
@john = create(:beatle, name: 'John')
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# and about 15 examples here
|
|
21
|
-
end
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Or you can try `before(:all)`:
|
|
25
|
-
|
|
26
|
-
```ruby
|
|
27
|
-
describe BeatleWeightedSearchQuery do
|
|
28
|
-
before(:all) do
|
|
29
|
-
@paul = create(:beatle, name: 'Paul')
|
|
30
|
-
# ...
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# ...
|
|
34
|
-
end
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
But then you have to deal with database cleaning, which can be either tricky or slow.
|
|
38
|
-
|
|
39
|
-
There is a better option: we can wrap the whole example group into a transaction.
|
|
40
|
-
And that's how `before_all` works:
|
|
41
|
-
|
|
42
|
-
```ruby
|
|
43
|
-
describe BeatleWeightedSearchQuery do
|
|
44
|
-
before_all do
|
|
45
|
-
@paul = create(:beatle, name: 'Paul')
|
|
46
|
-
# ...
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# ...
|
|
50
|
-
end
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
That's all!
|
|
54
|
-
|
|
55
|
-
## Instructions
|
|
56
|
-
|
|
57
|
-
In your `spec_helper.rb`:
|
|
58
|
-
|
|
59
|
-
```ruby
|
|
60
|
-
require 'test_prof/recipes/rspec/before_all'
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Caveats
|
|
64
|
-
|
|
65
|
-
If you modify objects generated within a `before_all` block in your examples, you maybe have to re-initiate them:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
before_all do
|
|
70
|
-
@user = create(:user)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
let(:user) { @user }
|
|
74
|
-
|
|
75
|
-
it 'when user is admin' do
|
|
76
|
-
# we modified our object in-place!
|
|
77
|
-
user.update!(role: 1)
|
|
78
|
-
expect(user).to be_admin
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'when user is regular' do
|
|
82
|
-
# now @user's state depends on the order of specs!
|
|
83
|
-
expect(user).not_to be_admin
|
|
84
|
-
end
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
The easiest way to solve this is to reload record for every example (it's still much faster than creating a new one):
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```ruby
|
|
91
|
-
before_all do
|
|
92
|
-
@user = create(:user)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Note, that @user.reload may not be enough,
|
|
96
|
-
# 'cause it doesn't reset associations
|
|
97
|
-
let(:user) { User.find(@user.id) }
|
|
98
|
-
```
|
data/guides/event_prof.md
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# EventProf
|
|
2
|
-
|
|
3
|
-
EventProf collects instrumentation (such as ActiveSupport::Notifications) metrics during your test suite run.
|
|
4
|
-
|
|
5
|
-
It works very similar to `rspec --profile` but can track arbitrary events.
|
|
6
|
-
|
|
7
|
-
Example output:
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
[TEST PROF INFO] EventProf results for sql.active_record
|
|
11
|
-
|
|
12
|
-
Total time: 00:00.256
|
|
13
|
-
Total events: 1031
|
|
14
|
-
|
|
15
|
-
Top 5 slowest suites (by time):
|
|
16
|
-
|
|
17
|
-
AnswersController (./spec/controllers/answers_controller_spec.rb:3) – 00:00.119 (549 / 20)
|
|
18
|
-
QuestionsController (./spec/controllers/questions_controller_spec.rb:3) – 00:00.105 (360 / 18)
|
|
19
|
-
CommentsController (./spec/controllers/comments_controller_spec.rb:3) – 00:00.032 (122 / 4)
|
|
20
|
-
|
|
21
|
-
Top 5 slowest tests (by time):
|
|
22
|
-
|
|
23
|
-
destroys question (./spec/controllers/questions_controller_spec.rb:38) – 00:00.022 (29)
|
|
24
|
-
change comments count (./spec/controllers/comments_controller_spec.rb:7) – 00:00.011 (34)
|
|
25
|
-
change Votes count (./spec/shared_examples/controllers/voted_examples.rb:23) – 00:00.008 (25)
|
|
26
|
-
change Votes count (./spec/shared_examples/controllers/voted_examples.rb:23) – 00:00.008 (32)
|
|
27
|
-
fails (./spec/shared_examples/controllers/invalid_examples.rb:3) – 00:00.007 (34)
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Instructions
|
|
32
|
-
|
|
33
|
-
Currently, EventProf supports only ActiveSupport::Notifications
|
|
34
|
-
|
|
35
|
-
To activate EventProf with:
|
|
36
|
-
|
|
37
|
-
### RSpec
|
|
38
|
-
|
|
39
|
-
Use `EVENT_PROF` environment variable set to event name:
|
|
40
|
-
|
|
41
|
-
```sh
|
|
42
|
-
# Collect SQL queries stats for every suite and example
|
|
43
|
-
EVENT_PROF='sql.active_record' rspec ...
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Minitest
|
|
47
|
-
|
|
48
|
-
Use `EVENT_PROF` environment variable set to event name:
|
|
49
|
-
|
|
50
|
-
```sh
|
|
51
|
-
# Collect SQL queries stats for every suite and example
|
|
52
|
-
EVENT_PROF='sql.active_record' rake test
|
|
53
|
-
```
|
|
54
|
-
or use CLI options as well:
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
# Run a specific file using CLI option
|
|
58
|
-
ruby test/my_super_test.rb --event-prof=sql.active_record
|
|
59
|
-
|
|
60
|
-
# Show the list of possible options:
|
|
61
|
-
ruby test/my_super_test.rb --help
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Using with Minitest::Reporters
|
|
65
|
-
|
|
66
|
-
If you're using `Minitest::Reporters` in your project you have to explicitly declare it
|
|
67
|
-
in your test helper file:
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
require 'minitest/reporters'
|
|
71
|
-
Minitest::Reporters.use! [YOUR_FAVORITE_REPORTERS]
|
|
72
|
-
```
|
|
73
|
-
#### NOTICE
|
|
74
|
-
When you have `minitest-reporters` installed as a gem but not declared in your `Gemfile`
|
|
75
|
-
make sure to always prepend your test run command with `bundle exec` (but we sure that you always do it).
|
|
76
|
-
Otherwise, you'll get an error caused by Minitest plugin system, which scans all the entries in the
|
|
77
|
-
`$LOAD_PATH` for any `minitest/*_plugin.rb`, thus initialization of `minitest-reporters` plugin which is
|
|
78
|
-
available in that case doesn't happens correctly.
|
|
79
|
-
|
|
80
|
-
See [Rails guides](http://guides.rubyonrails.org/active_support_instrumentation.html)
|
|
81
|
-
for the list of available events if you're using Rails.
|
|
82
|
-
|
|
83
|
-
If you're using [rom-rb](http://rom-rb.org) you might be interested in profiling `'sql.rom'` event.
|
|
84
|
-
|
|
85
|
-
### Configuration
|
|
86
|
-
|
|
87
|
-
By default, EventProf collects information only about top-level groups (aka suites),
|
|
88
|
-
but you can also profile individual examples. Just set the configuration option:
|
|
89
|
-
|
|
90
|
-
```ruby
|
|
91
|
-
TestProf::EventProf.configure do |config|
|
|
92
|
-
config.per_example = true
|
|
93
|
-
end
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Or provide the `EVENT_PROF_EXAMPLES=1` env variable.
|
|
97
|
-
|
|
98
|
-
Another useful configuration parameter – `rank_by`. It's responsible for sorting stats –
|
|
99
|
-
either by the time spent in the event or by the number of occurrences:
|
|
100
|
-
|
|
101
|
-
```sh
|
|
102
|
-
EVENT_PROF_RANK=count EVENT_PROF='instantiation.active_record' be rspec
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
See [event_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/event_prof.rb) for all available configuration options and their usage.
|
|
106
|
-
|
|
107
|
-
## Using with RSpecStamp
|
|
108
|
-
|
|
109
|
-
EventProf 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:
|
|
110
|
-
|
|
111
|
-
```sh
|
|
112
|
-
EVENT_PROF="sql.active_record" EVENT_PROF_STAMP="slow:sql" rspec ...
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
After running the command above the slowest example groups (and examples if configured) would be marked with the `slow: :sql` tag.
|
|
116
|
-
|
|
117
|
-
## Custom Instrumentation
|
|
118
|
-
|
|
119
|
-
To use EventProf with your instrumentation engine just complete the two following steps:
|
|
120
|
-
|
|
121
|
-
- Add a wrapper for your instrumentation:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```ruby
|
|
125
|
-
# Wrapper over your instrumentation
|
|
126
|
-
module MyEventsWrapper
|
|
127
|
-
# Should contain the only one method
|
|
128
|
-
def self.subscribe(event)
|
|
129
|
-
raise ArgumentError, 'Block is required!' unless block_given?
|
|
130
|
-
|
|
131
|
-
::MyEvents.subscribe(event) do |start, finish, *|
|
|
132
|
-
yield (finish - start)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
- Set instrumenter in the config:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
```ruby
|
|
142
|
-
TestProf::EventProf.configure do |config|
|
|
143
|
-
config.instrumenter = MyEventsWrapper
|
|
144
|
-
end
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Custom Events
|
|
148
|
-
|
|
149
|
-
### `"factory.create"`
|
|
150
|
-
|
|
151
|
-
FactoryGirl provides its own instrumentation ('factory_girl.run_factory'); but there is a caveat – it fires an event every time a factory is used, even when we use factory for nested associations. Thus it's not possible to calculate the total time spent in factories due to the double calculation.
|
|
152
|
-
|
|
153
|
-
EventProf comes with a little patch for FactoryGirl which provides instrumentation only for top-level `FactoryGirl.create` calls. It is loaded automatically if you use `"factory.create"` event:
|
|
154
|
-
|
|
155
|
-
```sh
|
|
156
|
-
EVENT_PROF=factory.create bundle exec rspec
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### `"sidekiq.jobs"`
|
|
160
|
-
|
|
161
|
-
Collects statistics about Sidekiq jobs that have been run inline:
|
|
162
|
-
|
|
163
|
-
```sh
|
|
164
|
-
EVENT_PROF=sidekiq.jobs bundle exec rspec
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
**NOTE**: automatically sets `rank_by` to `count` ('cause it doesn't make sense to collect the information about time spent – see below).
|
|
168
|
-
|
|
169
|
-
### `"sidekiq.inline"`
|
|
170
|
-
|
|
171
|
-
Collects statistics about Sidekiq jobs that have been run inline (excluding nested jobs):
|
|
172
|
-
|
|
173
|
-
```sh
|
|
174
|
-
EVENT_PROF=sidekiq.inline bundle exec rspec
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
Use this event to profile the time spent running Sidekiq jobs.
|
data/guides/factory_default.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# FactoryDefault
|
|
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 reusing associated records.
|
|
4
|
-
|
|
5
|
-
**NOTE**. Only works with FactoryGirl/FactoryBot.
|
|
6
|
-
|
|
7
|
-
It can be very useful when you're working on a typical SaaS application (or other hierarchical data).
|
|
8
|
-
|
|
9
|
-
Consider an example. Assume we have the following factories:
|
|
10
|
-
|
|
11
|
-
```ruby
|
|
12
|
-
factory :account do
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
factory :user do
|
|
16
|
-
account
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
factory :project do
|
|
20
|
-
account
|
|
21
|
-
user
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
factory :task do
|
|
25
|
-
account
|
|
26
|
-
project
|
|
27
|
-
user
|
|
28
|
-
end
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
And we want to test the `Task` model:
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
describe 'PATCH #update' do
|
|
35
|
-
let(:task) { create(:task) }
|
|
36
|
-
|
|
37
|
-
it 'works' do
|
|
38
|
-
patch :update, id: task.id, task: { completed: 't' }
|
|
39
|
-
expect(response).to be_success
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# ...
|
|
43
|
-
end
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
How many users and accounts are created per example? Two and four respectively.
|
|
47
|
-
|
|
48
|
-
And it breaks our logic (every object should belong to the same account).
|
|
49
|
-
|
|
50
|
-
Typical workaround:
|
|
51
|
-
|
|
52
|
-
```ruby
|
|
53
|
-
describe 'PATCH #update' do
|
|
54
|
-
let(:account) { create(:account) }
|
|
55
|
-
let(:project) { create(:project, account: account) }
|
|
56
|
-
let(:task) { create(:task, project: project, account: account) }
|
|
57
|
-
|
|
58
|
-
it 'works' do
|
|
59
|
-
patch :update, id: task.id, task: { completed: 't' }
|
|
60
|
-
expect(response).to be_success
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
That works. And there are some cons: it's a little bit verbose and error-prone (easy to forget something).
|
|
66
|
-
|
|
67
|
-
Here is how we can deal with it using FactoryDefault:
|
|
68
|
-
|
|
69
|
-
```ruby
|
|
70
|
-
describe 'PATCH #update' do
|
|
71
|
-
let(:account) { create_default(:account) }
|
|
72
|
-
let(:project) { create_default(:project) }
|
|
73
|
-
let(:task) { create(:task) }
|
|
74
|
-
|
|
75
|
-
# and if we need more projects, users, tasks with the same parent record,
|
|
76
|
-
# we just write
|
|
77
|
-
let(:another_project) { create(:project) } # uses the same account
|
|
78
|
-
let(:another_task) { create(:task) } # uses the same account
|
|
79
|
-
|
|
80
|
-
it 'works' do
|
|
81
|
-
patch :update, id: task.id, task: { completed: 't' }
|
|
82
|
-
expect(response).to be_success
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
**NOTE**. This feature introduces a bit of _magic_ to your tests, so use it with caution ('cause tests should be human-readable first). Good idea is to use defaults for top-level entities only (such as tenants in multi-tenancy apps).
|
|
88
|
-
|
|
89
|
-
## Instructions
|
|
90
|
-
|
|
91
|
-
In your `spec_helper.rb`:
|
|
92
|
-
|
|
93
|
-
```ruby
|
|
94
|
-
require 'test_prof/recipes/rspec/factory_default'
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This adds two new methods to FactoryBot:
|
|
98
|
-
|
|
99
|
-
- `FactoryBot#set_factory_default(factory, object)` – use the `object` as default for associations built with `factory`
|
|
100
|
-
|
|
101
|
-
Example:
|
|
102
|
-
|
|
103
|
-
```ruby
|
|
104
|
-
let(:user) { create(:user) }
|
|
105
|
-
|
|
106
|
-
before { FactoryBot.set_factory_default(:user, user) }
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
- `FactoryBot#create_default(factory, *args)` – is a shortcut for `create` + `set_factory_default`.
|
|
110
|
-
|
|
111
|
-
**NOTE**. Defaults are cleaned up after each example.
|