test-prof 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module FactoryDoctor
5
+ # Wrap #run method with FactoryDoctor tracking
6
+ module FabricationPatch
7
+ def create(*)
8
+ FactoryDoctor.within_factory(:create) { super }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof/ext/factory_bot_strategy"
4
+
3
5
  module TestProf
4
6
  module FactoryDoctor
5
7
  # Wrap #run method with FactoryDoctor tracking
6
8
  module FactoryBotPatch
9
+ using TestProf::FactoryBotStrategy
10
+
7
11
  def run(strategy = @strategy)
8
- FactoryDoctor.within_factory(strategy) { super }
12
+ FactoryDoctor.within_factory(strategy.create? ? :create : :other) { super }
9
13
  end
10
14
  end
11
15
  end
@@ -58,9 +58,15 @@ module TestProf
58
58
  MSG
59
59
 
60
60
  @example_groups.each do |group, examples|
61
- msgs << "#{group.description} (#{group.metadata[:location]})\n"
61
+ group_time = examples.sum { |ex| ex.metadata[:time] }
62
+ group_count = examples.sum { |ex| ex.metadata[:factories] }
63
+
64
+ msgs << "#{group.description} (#{group.metadata[:location]}) " \
65
+ "(#{pluralize_records(group_count)} created, " \
66
+ "#{group_time.duration})\n"
67
+
62
68
  examples.each do |ex|
63
- msgs << " #{ex.description} (#{ex.metadata[:location]}) "\
69
+ msgs << " #{ex.description} (#{ex.metadata[:location]}) " \
64
70
  "– #{pluralize_records(ex.metadata[:factories])} created, "\
65
71
  "#{ex.metadata[:time].duration}\n"
66
72
  end
@@ -36,15 +36,16 @@ module TestProf
36
36
 
37
37
  # Returns sorted stats
38
38
  def stats
39
- return @stats if instance_variable_defined?(:@stats)
39
+ @stats ||= @raw_stats.values
40
+ .sort_by { |el| -el[:total_count] }
41
+ end
40
42
 
41
- @stats = @raw_stats.values
42
- .sort_by { |el| -el[:total] }
43
+ def total_count
44
+ @total_count ||= @raw_stats.values.sum { |v| v[:total_count] }
43
45
  end
44
46
 
45
- def total
46
- return @total if instance_variable_defined?(:@total)
47
- @total = @raw_stats.values.sum { |v| v[:total] }
47
+ def total_time
48
+ @total_time ||= @raw_stats.values.sum { |v| v[:total_time] }
48
49
  end
49
50
 
50
51
  private
@@ -103,13 +104,18 @@ module TestProf
103
104
 
104
105
  def track(factory)
105
106
  return yield unless running?
107
+ @depth += 1
108
+ @current_stack << factory if config.flamegraph?
109
+ @stats[factory][:total_count] += 1
110
+ @stats[factory][:top_level_count] += 1 if @depth == 1
111
+ t1 = TestProf.now
106
112
  begin
107
- @depth += 1
108
- @current_stack << factory if config.flamegraph?
109
- @stats[factory][:total] += 1
110
- @stats[factory][:top_level] += 1 if @depth == 1
111
113
  yield
112
114
  ensure
115
+ t2 = TestProf.now
116
+ elapsed = t2 - t1
117
+ @stats[factory][:total_time] += elapsed
118
+ @stats[factory][:top_level_time] += elapsed if @depth == 1
113
119
  @depth -= 1
114
120
  flush_stack if @depth.zero?
115
121
  end
@@ -120,7 +126,15 @@ module TestProf
120
126
  def reset!
121
127
  @stacks = [] if config.flamegraph?
122
128
  @depth = 0
123
- @stats = Hash.new { |h, k| h[k] = {name: k, total: 0, top_level: 0} }
129
+ @stats = Hash.new do |h, k|
130
+ h[k] = {
131
+ name: k,
132
+ total_count: 0,
133
+ top_level_count: 0,
134
+ total_time: 0.0,
135
+ top_level_time: 0.0
136
+ }
137
+ end
124
138
  flush_stack
125
139
  end
126
140
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "test_prof/factory_prof/factory_bot_patch"
4
4
  require "test_prof/factory_bot"
5
+ require "test_prof/ext/factory_bot_strategy"
5
6
 
6
7
  module TestProf
7
8
  module FactoryProf
@@ -9,23 +10,7 @@ module TestProf
9
10
  # implementation of #patch and #track methods
10
11
  # to provide unified interface for all factory-building gems
11
12
  class FactoryBot
12
- # FactoryBot 5.0 uses strategy classes for associations,
13
- # older versions and top-level invocations use Symbols
14
- using(Module.new do
15
- refine Symbol do
16
- def create?
17
- self == :create
18
- end
19
- end
20
-
21
- if defined?(::FactoryBot::Strategy::Create)
22
- refine Class do
23
- def create?
24
- self <= ::FactoryBot::Strategy::Create
25
- end
26
- end
27
- end
28
- end)
13
+ using TestProf::FactoryBotStrategy
29
14
 
30
15
  # Monkey-patch FactoryBot / FactoryGirl
31
16
  def self.patch
@@ -15,7 +15,7 @@ module TestProf::FactoryProf
15
15
  return log(:info, "No factories detected") if result.raw_stats == {}
16
16
  report_data = {
17
17
  total_stacks: result.stacks.size,
18
- total: result.total
18
+ total: result.total_count
19
19
  }
20
20
 
21
21
  report_data[:roots] = convert_stacks(result)
@@ -45,7 +45,11 @@ module TestProf::FactoryProf
45
45
  node = paths[path]
46
46
  node[:value] += 1
47
47
  else
48
- node = {name: sample, value: 1, total: result.raw_stats.fetch(sample)[:total]}
48
+ node = {
49
+ name: sample,
50
+ value: 1,
51
+ total: result.raw_stats.fetch(sample)[:total_count]
52
+ }
49
53
  paths[path] = node
50
54
 
51
55
  if parent.nil?
@@ -10,23 +10,25 @@ module TestProf::FactoryProf
10
10
  return log(:info, "No factories detected") if result.raw_stats == {}
11
11
  msgs = []
12
12
 
13
- total = result.stats.sum { |stat| stat[:total] }
14
- total_top_level = result.stats.sum { |stat| stat[:top_level] }
13
+ total_count = result.stats.sum { |stat| stat[:total_count] }
14
+ total_top_level_count = result.stats.sum { |stat| stat[:top_level_count] }
15
+ total_time = result.stats.sum { |stat| stat[:top_level_time] }
15
16
  total_uniq_factories = result.stats.map { |stat| stat[:name] }.uniq.count
16
17
 
17
18
  msgs <<
18
19
  <<~MSG
19
20
  Factories usage
20
21
 
21
- Total: #{total}
22
- Total top-level: #{total_top_level}
22
+ Total: #{total_count}
23
+ Total top-level: #{total_top_level_count}
24
+ Total time: #{format("%.4f", total_time)}s
23
25
  Total uniq factories: #{total_uniq_factories}
24
26
 
25
- total top-level name
27
+ total top-level total time top-level time name
26
28
  MSG
27
29
 
28
30
  result.stats.each do |stat|
29
- msgs << format("%6d %11d %30s", stat[:total], stat[:top_level], stat[:name])
31
+ msgs << format("%8d %11d %11.4fs %15.4fs %30s", stat[:total_count], stat[:top_level_count], stat[:total_time], stat[:top_level_time], stat[:name])
30
32
  end
31
33
 
32
34
  log :info, msgs.join("\n")
@@ -7,7 +7,26 @@ module TestProf
7
7
  # Just like `let`, but persist the result for the whole group.
8
8
  # NOTE: Experimental and magical, for more control use `before_all`.
9
9
  module LetItBe
10
+ class Configuration
11
+ # Define an alias for `let_it_be` with the predefined options:
12
+ #
13
+ # TestProf::LetItBe.configure do |config|
14
+ # config.alias_to :let_it_be_reloaded, reload: true
15
+ # end
16
+ def alias_to(name, **default_args)
17
+ LetItBe.define_let_it_be_alias(name, **default_args)
18
+ end
19
+ end
20
+
10
21
  class << self
22
+ def config
23
+ @config ||= Configuration.new
24
+ end
25
+
26
+ def configure
27
+ yield config
28
+ end
29
+
11
30
  def module_for(group)
12
31
  modules[group] ||= begin
13
32
  Module.new.tap { |mod| group.prepend(mod) }
@@ -25,6 +44,12 @@ module TestProf
25
44
  # And we love cats!)
26
45
  PREFIX = RUBY_ENGINE == "jruby" ? "@__jruby_is_not_cat_friendly__" : "@😸"
27
46
 
47
+ def self.define_let_it_be_alias(name, **default_args)
48
+ define_method(name) do |identifier, **options, &blk|
49
+ let_it_be(identifier, default_args.merge(options), &blk)
50
+ end
51
+ end
52
+
28
53
  def let_it_be(identifier, **options, &block)
29
54
  initializer = proc do
30
55
  instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.8.0"
4
+ VERSION = "0.9.0"
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.8.0
4
+ version: 0.9.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: 2019-04-13 00:00:00.000000000 Z
11
+ date: 2019-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '5.9'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.65.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.65.0
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: rubocop-md
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +100,14 @@ dependencies:
114
100
  requirements:
115
101
  - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: 0.0.36
103
+ version: 0.0.39
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
108
  - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: 0.0.36
110
+ version: 0.0.39
125
111
  description: "\n Ruby applications tests profiling tools.\n\n Contains tools
126
112
  to analyze factories usage, integrate with Ruby profilers,\n profile your examples
127
113
  using ActiveSupport notifications (if any) and\n statically analyze your code
@@ -170,6 +156,7 @@ files:
170
156
  - lib/test_prof/ext/active_record_3.rb
171
157
  - lib/test_prof/ext/active_record_refind.rb
172
158
  - lib/test_prof/ext/array_bsearch_index.rb
159
+ - lib/test_prof/ext/factory_bot_strategy.rb
173
160
  - lib/test_prof/ext/float_duration.rb
174
161
  - lib/test_prof/ext/string_truncate.rb
175
162
  - lib/test_prof/factory_all_stub.rb
@@ -178,6 +165,7 @@ files:
178
165
  - lib/test_prof/factory_default.rb
179
166
  - lib/test_prof/factory_default/factory_bot_patch.rb
180
167
  - lib/test_prof/factory_doctor.rb
168
+ - lib/test_prof/factory_doctor/fabrication_patch.rb
181
169
  - lib/test_prof/factory_doctor/factory_bot_patch.rb
182
170
  - lib/test_prof/factory_doctor/minitest.rb
183
171
  - lib/test_prof/factory_doctor/rspec.rb
@@ -226,7 +214,12 @@ files:
226
214
  homepage: http://github.com/palkan/test-prof
227
215
  licenses:
228
216
  - MIT
229
- metadata: {}
217
+ metadata:
218
+ bug_tracker_uri: http://github.com/palkan/test-prof/issues
219
+ changelog_uri: https://github.com/palkan/test-prof/blob/master/CHANGELOG.md
220
+ documentation_uri: https://test-prof.evilmartians.io/
221
+ homepage_uri: https://test-prof.evilmartians.io/
222
+ source_code_uri: http://github.com/palkan/test-prof
230
223
  post_install_message:
231
224
  rdoc_options: []
232
225
  require_paths:
@@ -242,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
235
  - !ruby/object:Gem::Version
243
236
  version: '0'
244
237
  requirements: []
245
- rubygems_version: 3.0.2
238
+ rubygems_version: 3.0.3
246
239
  signing_key:
247
240
  specification_version: 4
248
241
  summary: Ruby applications tests profiling tools