test-prof 0.1.0.beta3 → 0.1.0.beta4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58805aeec9869d4d5b15a7a936ff1f0f10c6b7cb
4
- data.tar.gz: 6e89ccd56db3e421d5660573ea4cfea9dceb8010
3
+ metadata.gz: 4bebeb0abae778ec18d0ec11538784b0255bd26d
4
+ data.tar.gz: '098fa4a951eba03ac7fcda3e6565ca01936dd182'
5
5
  SHA512:
6
- metadata.gz: b1985d22be179fffe92e3a1f87bf76eb5b08a4667195badd55c3caa9e4705462358708e6c9362a14cfbaf0928e0ed23baa65e3358a42b773426c567007915d83
7
- data.tar.gz: 96fd3e35e266b7e5cdb2558bab332a63b0d7ccc0233866444d108a7b7549e9ffbe528d2b51b44ab558ebb80947d49c061cf69c92bec9161117c4b337d7c61c0e
6
+ metadata.gz: 1099d6a1805f71697cccbb555025bffba6589e87016e33d715a046368e20dda1d5d1b2df259792b144c2ba0e7f816f64e6dd745f14114b1bb4ee6446e2edbba2
7
+ data.tar.gz: 4212b16b0487b6a5c4853e855a07278778cc487f0b378148d4903e180d20a935e3110542bdaf553070f499ddce220a046366b2b18049ae598b6dc36e4a54e0dc
data/README.md CHANGED
@@ -31,6 +31,8 @@ See [Table of Contents](#table-of-contents) for more.
31
31
 
32
32
  - RubyConfBy, 2017, "Run Test Run" talk [[video](https://www.youtube.com/watch?v=q52n4p0wkIs), [slides](https://speakerdeck.com/palkan/rubyconfby-minsk-2017-run-test-run)]
33
33
 
34
+ - [Tips to improve speed of your test suite](https://medium.com/appaloosa-store-engineering/tips-to-improve-speed-of-your-test-suite-8418b485205c) by [Benoit Tigeot](https://github.com/benoittgt)
35
+
34
36
  ## Installation
35
37
 
36
38
  Add `test-prof` gem to your application:
@@ -69,8 +71,12 @@ We also want to share some small code tricks which can help you to improve your
69
71
 
70
72
  - [AnyFixture](https://github.com/palkan/test-prof/tree/master/guides/any_fixture.md)
71
73
 
74
+ - [FactoryDefault](https://github.com/palkan/test-prof/tree/master/guides/factory_default.md)
75
+
72
76
  - [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md)
73
77
 
78
+ - [Tests Sampling](https://github.com/palkan/test-prof/tree/master/guides/tests_sampling.md)
79
+
74
80
  ## Configuration
75
81
 
76
82
  TestProf global configuration is used by most of the profilers:
@@ -0,0 +1,109 @@
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 re-using associated records.
4
+
5
+ It can be very useful when you're working on a typical SaaS application (or other hierarchical data).
6
+
7
+ Consider an example. Assume we have the following factories:
8
+
9
+ ```ruby
10
+ factory :account do
11
+ end
12
+
13
+ factory :user do
14
+ account
15
+ end
16
+
17
+ factory :project do
18
+ account
19
+ user
20
+ end
21
+
22
+ factory :task do
23
+ account
24
+ project
25
+ user
26
+ end
27
+ ```
28
+
29
+ And we want to test the `Task` model:
30
+
31
+ ```ruby
32
+ describe "PATCH #update" do
33
+ let(:task( { create(:task) }
34
+
35
+ it "works" do
36
+ patch :update, id: task.id, task: { completed: 't' }
37
+ expect(response).to be_success
38
+ end
39
+
40
+ ...
41
+ end
42
+ ```
43
+
44
+ How many users and accounts are created per example? Two and four respectively.
45
+
46
+ And it breaks our logic (every object should belong to the same account).
47
+
48
+ Typical workaround:
49
+
50
+ ```ruby
51
+ describe "PATCH #update" do
52
+ let(:account) { create(:account) }
53
+ let(:project) { create(:project, account: account) }
54
+ let(:task( { create(:task, project: project, account: account) }
55
+
56
+ it "works" do
57
+ patch :update, id: task.id, task: { completed: 't' }
58
+ expect(response).to be_success
59
+ end
60
+ end
61
+ ```
62
+
63
+ That works. And there are some cons: it's a little bit verbose and error-prone (easy to forget something).
64
+
65
+ Here is how we can deal with it using FactoryDefault:
66
+
67
+ ```ruby
68
+ describe "PATCH #update" do
69
+ let(:account) { create_default(:account) }
70
+ let(:project) { create_default(:project) }
71
+ let(:task( { create(:task) }
72
+
73
+ # and if need more projects, users, tasks with the same parent record,
74
+ # we just write
75
+ let(:another_project) { create(:project) } # uses the same account
76
+ let(:another_task) { create(:task) } # uses the same account and the first project
77
+
78
+ it "works" do
79
+ patch :update, id: task.id, task: { completed: 't' }
80
+ expect(response).to be_success
81
+ end
82
+ end
83
+ ```
84
+
85
+ *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).
86
+
87
+ ## Instructions
88
+
89
+ In your `spec_helper.rb`:
90
+
91
+ ```ruby
92
+ require "test_prof/recipes/rspec/factory_default"
93
+ ```
94
+
95
+ This adds two new methods to FactoryGirl:
96
+
97
+ - `FactoryGirl#set_factory_default(factory, object)` – use the `object` as default for associations built with `factory`
98
+
99
+ Example:
100
+
101
+ ```ruby
102
+ let(:user) { create(:user) }
103
+
104
+ before { FactoryGirl.set_factory_default(:user, user) }
105
+ ```
106
+
107
+ - `FactoryGirl#create_default(factory, *args)` – is a shortcut for `create` + `set_factory_default`.
108
+
109
+ *NOTE*. Defaults are cleaned up after each example.
@@ -0,0 +1,24 @@
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!
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/factory_default/factory_girl_patch"
4
+
5
+ module TestProf
6
+ # FactoryDefault allows use to re-use associated objects
7
+ # in factories implicilty
8
+ module FactoryDefault
9
+ module DefaultSyntax # :nodoc:
10
+ def create_default(name, *args, &block)
11
+ set_factory_default(
12
+ name,
13
+ FactoryGirl.create(name, *args, &block)
14
+ )
15
+ end
16
+
17
+ def set_factory_default(name, obj)
18
+ FactoryDefault.register(name, obj)
19
+ end
20
+ end
21
+
22
+ class << self
23
+ def init
24
+ FactoryGirl::Syntax::Methods.include DefaultSyntax
25
+ FactoryGirl.extend DefaultSyntax
26
+ FactoryGirl::Strategy::Create.prepend StrategyExt
27
+ FactoryGirl::Strategy::Build.prepend StrategyExt
28
+ FactoryGirl::Strategy::Stub.prepend StrategyExt
29
+
30
+ @store = {}
31
+ end
32
+
33
+ def register(name, obj)
34
+ store[name] = obj
35
+ end
36
+
37
+ def get(name)
38
+ store[name]
39
+ end
40
+
41
+ def exists?(name)
42
+ store.key?(name)
43
+ end
44
+
45
+ def remove(name)
46
+ store.delete(name)
47
+ end
48
+
49
+ def reset
50
+ @store.clear
51
+ end
52
+
53
+ private
54
+
55
+ attr_reader :store
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module FactoryDefault # :nodoc: all
5
+ module RunnerExt
6
+ refine FactoryGirl::FactoryRunner do
7
+ def name
8
+ @name
9
+ end
10
+ end
11
+ end
12
+
13
+ using RunnerExt
14
+
15
+ module StrategyExt
16
+ def association(runner)
17
+ return super unless FactoryDefault.exists?(runner.name)
18
+ FactoryDefault.get(runner.name)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ # Add ability to run only a specified number of example groups (randomly selected)
5
+ module MinitestSample
6
+ # Do not add these classes to resulted sample
7
+ CORE_RUNNABLES = [
8
+ Minitest::Test,
9
+ Minitest::Unit::TestCase,
10
+ Minitest::Spec
11
+ ].freeze
12
+
13
+ def run(*)
14
+ unless ENV['SAMPLE'].nil?
15
+ sample_size = ENV['SAMPLE'].to_i
16
+ # Make sure that sample contains only _real_ suites
17
+ runnables = Minitest::Runnable.runnables
18
+ .sample(sample_size + CORE_RUNNABLES.size)
19
+ .reject { |suite| CORE_RUNNABLES.include?(suite) }
20
+ .take(sample_size)
21
+ Minitest::Runnable.reset
22
+ runnables.each { |r| Minitest::Runnable.runnables << r }
23
+ end
24
+ super
25
+ end
26
+ end
27
+ end
28
+
29
+ Minitest.singleton_class.prepend(TestProf::MinitestSample)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/factory_default"
4
+
5
+ TestProf::FactoryDefault.init
6
+
7
+ RSpec.configure do |config|
8
+ config.after(:each) { TestProf::FactoryDefault.reset }
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ # Add ability to run only a specified number of example groups (randomly selected)
5
+ module RspecSample
6
+ def ordered_example_groups
7
+ @example_groups = @example_groups.sample(ENV['SAMPLE'].to_i) unless ENV['SAMPLE'].nil?
8
+ super
9
+ end
10
+ end
11
+ end
12
+
13
+ RSpec::Core::World.prepend(TestProf::RspecSample)
@@ -83,6 +83,16 @@ module TestProf
83
83
  ::StackProf.results(path)
84
84
 
85
85
  log :info, "StackProf report generated: #{path}"
86
+
87
+ return unless config.raw
88
+
89
+ html_path = path.gsub(/\.dump$/, '.html')
90
+
91
+ log :info, <<~MSG
92
+ Run the following command to generate a flame graph report:
93
+
94
+ stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
95
+ MSG
86
96
  end
87
97
 
88
98
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.1.0.beta3"
4
+ VERSION = "0.1.0.beta4"
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.1.0.beta3
4
+ version: 0.1.0.beta4
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-07-24 00:00:00.000000000 Z
11
+ date: 2017-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.9'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: activerecord
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -161,6 +175,7 @@ files:
161
175
  - guides/any_fixture.md
162
176
  - guides/before_all.md
163
177
  - guides/event_prof.md
178
+ - guides/factory_default.md
164
179
  - guides/factory_doctor.md
165
180
  - guides/factory_prof.md
166
181
  - guides/rspec_stamp.md
@@ -168,6 +183,7 @@ files:
168
183
  - guides/ruby_prof.md
169
184
  - guides/stack_prof.md
170
185
  - guides/tag_prof.md
186
+ - guides/tests_sampling.md
171
187
  - lib/test-prof.rb
172
188
  - lib/test_prof.rb
173
189
  - lib/test_prof/any_fixture.rb
@@ -181,6 +197,8 @@ files:
181
197
  - lib/test_prof/event_prof/minitest.rb
182
198
  - lib/test_prof/event_prof/rspec.rb
183
199
  - lib/test_prof/ext/float_duration.rb
200
+ - lib/test_prof/factory_default.rb
201
+ - lib/test_prof/factory_default/factory_girl_patch.rb
184
202
  - lib/test_prof/factory_doctor.rb
185
203
  - lib/test_prof/factory_doctor/factory_girl_patch.rb
186
204
  - lib/test_prof/factory_doctor/minitest.rb
@@ -190,8 +208,11 @@ files:
190
208
  - lib/test_prof/factory_prof/printers/flamegraph.rb
191
209
  - lib/test_prof/factory_prof/printers/simple.rb
192
210
  - lib/test_prof/logging.rb
211
+ - lib/test_prof/recipes/minitest/sample.rb
193
212
  - lib/test_prof/recipes/rspec/any_fixture.rb
194
213
  - lib/test_prof/recipes/rspec/before_all.rb
214
+ - lib/test_prof/recipes/rspec/factory_default.rb
215
+ - lib/test_prof/recipes/rspec/sample.rb
195
216
  - lib/test_prof/rspec_stamp.rb
196
217
  - lib/test_prof/rspec_stamp/parser.rb
197
218
  - lib/test_prof/rspec_stamp/rspec.rb