test-prof 0.1.0.beta3 → 0.1.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
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