rspec-benchmark 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +28 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +137 -0
- data/Rakefile +10 -0
- data/lib/rspec-benchmark.rb +3 -0
- data/lib/rspec/benchmark.rb +7 -0
- data/lib/rspec/benchmark/format_time.rb +29 -0
- data/lib/rspec/benchmark/iteration_matcher.rb +62 -0
- data/lib/rspec/benchmark/matchers.rb +53 -0
- data/lib/rspec/benchmark/timing_matcher.rb +105 -0
- data/lib/rspec/benchmark/version.rb +7 -0
- data/rspec-benchmark.gemspec +26 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/unit/format_time_spec.rb +21 -0
- data/spec/unit/perform_at_least_spec.rb +34 -0
- data/spec/unit/perform_under_spec.rb +53 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +34 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7284782b6fbaacc643bbe29f58c30aa05985b9c7
|
4
|
+
data.tar.gz: 8e5fd4afde4a6cba55e537d8399652a286675021
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 72f9771b9edea737412eb8e241d70f4dd56866632c267ce72b71719567cd0b19d7769b4425067050d90ae84bd049a0cc6f75e17f2da97f1fdcc92747b2bea06f
|
7
|
+
data.tar.gz: 951f9b31da5bea5c0df8db36fc2a2a2befeef46d92e061f5dcc8e08f6c08489f36035f40e3321199439f961ec27eeb5f28fbe48daed4da87bf612c5e85f63023
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
---
|
2
|
+
language: ruby
|
3
|
+
sudo: false
|
4
|
+
cache: bundler
|
5
|
+
bundler_args: --without yard benchmarks
|
6
|
+
script: "bundle exec rake ci"
|
7
|
+
rvm:
|
8
|
+
- 1.9.3
|
9
|
+
- 2.0
|
10
|
+
- 2.1
|
11
|
+
- 2.2
|
12
|
+
- ruby-head
|
13
|
+
- jruby-19mode
|
14
|
+
- jruby
|
15
|
+
- jruby-head
|
16
|
+
- rbx-2
|
17
|
+
env:
|
18
|
+
global:
|
19
|
+
- JRUBY_OPTS="-Xcli.debug=true --debug"
|
20
|
+
matrix:
|
21
|
+
allow_failures:
|
22
|
+
- rvm: ruby-head
|
23
|
+
- rvm: jruby-head
|
24
|
+
fast_finish: true
|
25
|
+
branches:
|
26
|
+
only: master
|
27
|
+
notifications:
|
28
|
+
email: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2016 Piotr Murach
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# RSpec::Benchmark
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/rspec-benchmark.svg)][gem]
|
3
|
+
[![Build Status](https://secure.travis-ci.org/peter-murach/rspec-benchmark.svg?branch=master)][travis]
|
4
|
+
[![Code Climate](https://codeclimate.com/github/peter-murach/rspec-benchmark/badges/gpa.svg)][codeclimate]
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/peter-murach/rspec-benchmark/badge.svg?branch=master)][coverage]
|
6
|
+
[![Inline docs](http://inch-ci.org/github/peter-murach/rspec-benchmark.svg?branch=master)][inchpages]
|
7
|
+
|
8
|
+
[gem]: http://badge.fury.io/rb/rspec-benchmark
|
9
|
+
[travis]: http://travis-ci.org/peter-murach/rspec-benchmark
|
10
|
+
[codeclimate]: https://codeclimate.com/github/peter-murach/rspec-benchmark
|
11
|
+
[coverage]: https://coveralls.io/github/peter-murach/rspec-benchmark?branch=master
|
12
|
+
[inchpages]: http://inch-ci.org/github/peter-murach/rspec-benchmark
|
13
|
+
|
14
|
+
> Performance testing matchers for RSpec
|
15
|
+
|
16
|
+
**RSpec::Benchmark** uses [benchmark-perf](https://github.com/peter-murach/benchmark-perf) for measurements.
|
17
|
+
|
18
|
+
## Why?
|
19
|
+
|
20
|
+
Integration and unit tests ensure that changing code maintains expected functionality. What is not guaranteed is the code changes impact on library performance. It is easy to refactor your way out of fast to slow code.
|
21
|
+
|
22
|
+
If you are new to performance testing you may find [Caveats](#3-caveats) section helpful.
|
23
|
+
|
24
|
+
## Contents
|
25
|
+
|
26
|
+
* [1. Usage](#1-usage)
|
27
|
+
* [2. Filtering](#2-filtering)
|
28
|
+
* [3. Caveats](#3-caveats)
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
gem 'rspec-benchmark'
|
36
|
+
```
|
37
|
+
|
38
|
+
And then execute:
|
39
|
+
|
40
|
+
$ bundle
|
41
|
+
|
42
|
+
Or install it yourself as:
|
43
|
+
|
44
|
+
$ gem install rspec-benchmark
|
45
|
+
|
46
|
+
## 1. Usage
|
47
|
+
|
48
|
+
For matchers to be available globally, in `spec_helper.rb` do:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require 'rspec-benchmark'
|
52
|
+
|
53
|
+
RSpec.configure do |config|
|
54
|
+
config.include RSpec::Benchmark::Matchers
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
This will add the `perform_under` and `perform_at_least` matchers to express expected performance benchmark from code executed inside the expectation.
|
59
|
+
|
60
|
+
Alternatively, you can add matchers for particular example:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
RSpec.describe "Performance testing" do
|
64
|
+
include RSpec::Benchmark::Matchers
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
### 1.1 Execution time
|
69
|
+
|
70
|
+
The `perform_under` matcher answers the question of how long does it take to perform a given block of code on average. The measurements are taken executing the block of code in a child process for accurent cpu times.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
expect { ... }.to perform_under(0.01).sec
|
74
|
+
```
|
75
|
+
|
76
|
+
All measurements are assumed to be expressed as seconds. However, you can also provide time in `ms`, `us` and `ns`. The equivalent example in `ms` would be:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
expect { ... }.to perform_under(10).ms
|
80
|
+
```
|
81
|
+
|
82
|
+
by default the above code will be sampled `30` times but you can change this by using `and_sample` like so:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
expect { ... }.to perform_under(0.01).and_sample(10)
|
86
|
+
```
|
87
|
+
|
88
|
+
### 1.2 Iterations
|
89
|
+
|
90
|
+
The `perform_at_least` matcher allows you to establish performance benchmark of how many iterations per second a given block of code should perform. For example, to expect a given code to perform at least 10K iterations per second do:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
expect { ... }.to perform_at_least(10000).ips
|
94
|
+
```
|
95
|
+
|
96
|
+
The `ips` part is optional but its usage clarifies the intent.
|
97
|
+
|
98
|
+
## 2 Filtering
|
99
|
+
|
100
|
+
Usually performance tests are best left for CI or occasional runs that do not affect TDD/BDD cycle. To achieve isolation you can use RSpec filters. For instance, in `spec_helper`:
|
101
|
+
|
102
|
+
```
|
103
|
+
config.filter_run_excluding performance: true
|
104
|
+
```
|
105
|
+
|
106
|
+
and then in your example group do:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
RSpec.describe ..., performance: true do
|
110
|
+
...
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Another option is to simply isolate the performance specs in separate directory suc as `spec/performance/...` and add custom rake task.
|
115
|
+
|
116
|
+
## 3 Caveats
|
117
|
+
|
118
|
+
When writing performance tests things to be mindful are:
|
119
|
+
|
120
|
+
+ The tests may **potentially be flaky** thus its best to use sensible boundaries:
|
121
|
+
- **too strict** boundaries may cause false positives, making tests fail
|
122
|
+
- **too relaxed** boundaries may also lead to false positives missing actual performance regressions
|
123
|
+
+ Generally performance tests will be **slow**, but you may try to avoid _unnecessarily_ slow tests by choosing smaller maximum value for sampling
|
124
|
+
|
125
|
+
If you have any other observations please share them!
|
126
|
+
|
127
|
+
## Contributing
|
128
|
+
|
129
|
+
1. Fork it ( https://github.com/peter-murach/rspec-benchmark/fork )
|
130
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
131
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
132
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
133
|
+
5. Create a new Pull Request
|
134
|
+
|
135
|
+
## Copyright
|
136
|
+
|
137
|
+
Copyright (c) 2016 Piotr Murach. See LICENSE for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Benchmark
|
5
|
+
# Format time for easy matcher reporting
|
6
|
+
#
|
7
|
+
# @param [Float] time
|
8
|
+
# the time to format
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
# the human readable time value
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def format_time(time)
|
15
|
+
if time >= 100.0
|
16
|
+
"%.0f sec" % [time]
|
17
|
+
elsif time >= 1.0
|
18
|
+
"%.3g sec" % [time]
|
19
|
+
elsif time >= 1e-3
|
20
|
+
"%.3g ms" % [time * 1e3]
|
21
|
+
elsif time >= 1e-6
|
22
|
+
"%.3g μs" % [time * 1e6]
|
23
|
+
else
|
24
|
+
"%.0f ns" % [time * 1e9]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
module_function :format_time
|
28
|
+
end # Benchmark
|
29
|
+
end # RSpec
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Benchmark
|
5
|
+
module IterationMatcher
|
6
|
+
# Implements the `perform_at_least` matcher
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Matcher
|
10
|
+
def initialize(iterations, options = {})
|
11
|
+
@iterations = iterations
|
12
|
+
end
|
13
|
+
|
14
|
+
# Indicates this matcher matches against a block
|
15
|
+
#
|
16
|
+
# @return [True]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def supports_block_expectations?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Boolean]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
def matches?(block)
|
27
|
+
@bench = ::Benchmark::Perf::Iteration.new
|
28
|
+
@average, @stddev, _ = @bench.run(&block)
|
29
|
+
@iterations <= (@average + 3 * @stddev)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ips
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
"expected block to #{description}, but #{positive_failure_reason}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_message_when_negated
|
41
|
+
"expected block not to #{description}, but #{negative_failure_reason}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def description
|
45
|
+
"perform at least #{@iterations} i/s"
|
46
|
+
end
|
47
|
+
|
48
|
+
def actual
|
49
|
+
"%d (± %d%%) i/s" % [@average, (@stddev / @average.to_f) * 100]
|
50
|
+
end
|
51
|
+
|
52
|
+
def positive_failure_reason
|
53
|
+
"performed only #{actual}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def negative_failure_reason
|
57
|
+
"performed #{actual}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end # IterationMatcher
|
61
|
+
end # Benchmark
|
62
|
+
end # RSpec
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rspec/benchmark/timing_matcher'
|
4
|
+
require 'rspec/benchmark/iteration_matcher'
|
5
|
+
|
6
|
+
module RSpec
|
7
|
+
module Benchmark
|
8
|
+
# Provides a number of useful performance testing expectations
|
9
|
+
#
|
10
|
+
# These matchers can be exposed by including the this module in
|
11
|
+
# a spec:
|
12
|
+
#
|
13
|
+
# RSpec.describe "Performance testing" do
|
14
|
+
# include RSpec::Benchmark::Matchers
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# or you can include in globablly in a spec_helper.rb file:
|
18
|
+
#
|
19
|
+
# RSpec.configure do |config|
|
20
|
+
# config.inlucde(RSpec::Benchmark::Matchers)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
module Matchers
|
25
|
+
# Passes if code block performs at least iterations
|
26
|
+
#
|
27
|
+
# @param [Integer] iterations
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# expect { ... }.to perform_at_least(10000)
|
31
|
+
# expect { ... }.to perform_at_least(10000).ips
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def perform_at_least(iterations, options = {})
|
35
|
+
IterationMatcher::Matcher.new(iterations, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Passes if code block performs under threshold
|
39
|
+
#
|
40
|
+
# @param [Float] threshold
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# expect { ... }.to peform_under(0.001)
|
44
|
+
# expect { ... }.to peform_under(0.001).sec
|
45
|
+
# expect { ... }.to peform_under(10).ms
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def perform_under(threshold, options = {})
|
49
|
+
TimingMatcher::Matcher.new(threshold, options)
|
50
|
+
end
|
51
|
+
end # Matchers
|
52
|
+
end # Benchmark
|
53
|
+
end # RSpec
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Benchmark
|
5
|
+
module TimingMatcher
|
6
|
+
# Implements the `perform_under` matcher
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Matcher
|
10
|
+
include RSpec::Benchmark
|
11
|
+
|
12
|
+
attr_reader :threshold
|
13
|
+
|
14
|
+
def initialize(threshold, options = {})
|
15
|
+
@threshold = threshold
|
16
|
+
@samples = options.fetch(:samples) { 30 }
|
17
|
+
@scale = threshold.to_s.split(/\./).last.size
|
18
|
+
@block = nil
|
19
|
+
@confidence_interval = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# Indicates this matcher matches against a block
|
23
|
+
#
|
24
|
+
# @return [True]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def supports_block_expectations?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Boolean]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
def matches?(block)
|
35
|
+
@block = block
|
36
|
+
return false unless block.is_a?(Proc)
|
37
|
+
@bench = ::Benchmark::Perf::ExecutionTime.new
|
38
|
+
@average, @stddev = @bench.run(@samples, &block)
|
39
|
+
@average <= @threshold
|
40
|
+
end
|
41
|
+
|
42
|
+
def does_not_match?(block)
|
43
|
+
!matches?(block) && block.is_a?(Proc)
|
44
|
+
end
|
45
|
+
|
46
|
+
def and_sample(samples)
|
47
|
+
@samples = samples
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def secs
|
52
|
+
self
|
53
|
+
end
|
54
|
+
alias_method :sec, :secs
|
55
|
+
|
56
|
+
# Tell this matcher to convert threshold to ms
|
57
|
+
# @api public
|
58
|
+
def ms
|
59
|
+
@threshold /= 1e3
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Tell this matcher to convert threshold to us
|
64
|
+
# @api public
|
65
|
+
def us
|
66
|
+
@threshold /= 1e6
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
# Tell this matcher to convert threshold to ns
|
71
|
+
# @api public
|
72
|
+
def ns
|
73
|
+
@threshold /= 1e9
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def failure_message
|
78
|
+
"expected block to #{description}, but #{positive_failure_reason}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def failure_message_when_negated
|
82
|
+
"expected block to not #{description}, but #{negative_failure_reason}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def description
|
86
|
+
"perform under #{format_time(@threshold)}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def actual
|
90
|
+
"#{format_time(@average)} (± #{format_time(@stddev)})"
|
91
|
+
end
|
92
|
+
|
93
|
+
def positive_failure_reason
|
94
|
+
return 'was not a block' unless @block.is_a?(Proc)
|
95
|
+
"performed above #{actual} "
|
96
|
+
end
|
97
|
+
|
98
|
+
def negative_failure_reason
|
99
|
+
return 'was not a block' unless @block.is_a?(Proc)
|
100
|
+
"performed #{actual} under"
|
101
|
+
end
|
102
|
+
end # Matcher
|
103
|
+
end # TiminingMatcher
|
104
|
+
end # Benchmark
|
105
|
+
end # RSpec
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rspec/benchmark/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rspec-benchmark"
|
8
|
+
spec.version = RSpec::Benchmark::VERSION
|
9
|
+
spec.authors = ["Piotr Murach"]
|
10
|
+
spec.email = [""]
|
11
|
+
spec.summary = %q{Performance testing matchers for RSpec}
|
12
|
+
spec.description = %q{Performance testing matchers for RSpec that provide simple way to specify speed benchmark expectations}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'benchmark-perf', '~> 0.1.0'
|
22
|
+
spec.add_dependency 'rspec', '>= 3.0.0', '< 4.0.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
|
4
|
+
require 'simplecov'
|
5
|
+
require 'coveralls'
|
6
|
+
|
7
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
Coveralls::SimpleCov::Formatter
|
10
|
+
]
|
11
|
+
|
12
|
+
SimpleCov.start do
|
13
|
+
command_name 'spec'
|
14
|
+
add_filter 'spec'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'rspec-benchmark'
|
19
|
+
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.include(RSpec::Benchmark::Matchers)
|
22
|
+
|
23
|
+
config.expect_with :rspec do |expectations|
|
24
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
25
|
+
end
|
26
|
+
|
27
|
+
config.mock_with :rspec do |mocks|
|
28
|
+
mocks.verify_partial_doubles = true
|
29
|
+
end
|
30
|
+
|
31
|
+
config.filter_run :focus
|
32
|
+
config.run_all_when_everything_filtered = true
|
33
|
+
|
34
|
+
config.disable_monkey_patching!
|
35
|
+
|
36
|
+
config.warnings = true
|
37
|
+
|
38
|
+
if config.files_to_run.one?
|
39
|
+
config.default_formatter = 'doc'
|
40
|
+
end
|
41
|
+
|
42
|
+
config.profile_examples = 2
|
43
|
+
|
44
|
+
config.order = :random
|
45
|
+
|
46
|
+
Kernel.srand config.seed
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe RSpec::Benchmark, '#format_time' do
|
4
|
+
{
|
5
|
+
1e-10 => "0 ns",
|
6
|
+
0.42e-6 => "420 ns",
|
7
|
+
3.4e-6 => "3.4 μs",
|
8
|
+
34e-6 => "34 μs",
|
9
|
+
340e-6 => "340 μs",
|
10
|
+
1e-3 => "1 ms",
|
11
|
+
12e-3 => "12 ms",
|
12
|
+
1.0 => "1 sec",
|
13
|
+
1.2345 => "1.23 sec",
|
14
|
+
123.45 => "123 sec",
|
15
|
+
1234 => "1234 sec"
|
16
|
+
}.each do |input, expected|
|
17
|
+
it "#{input} -> #{expected}" do
|
18
|
+
expect(described_class.format_time(input)).to eq(expected)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe '#perform_at_least' do
|
4
|
+
|
5
|
+
context "expect { ... }.to perform_at_least(...).ips" do
|
6
|
+
it "passes if the block perfoms more than 10K ips" do
|
7
|
+
expect {
|
8
|
+
'x' * 1024 * 10
|
9
|
+
}.to perform_at_least(10_000).ips
|
10
|
+
end
|
11
|
+
|
12
|
+
it "fails if the block performs less than 10K ips" do
|
13
|
+
expect {
|
14
|
+
expect {
|
15
|
+
'x' * 1024 * 1024
|
16
|
+
}.to perform_at_least(10_000).ips
|
17
|
+
}.to raise_error(/expected block to perform at least 10000 i\/s, but performed only \d+ \(± \d+%\) i\/s/)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "expect { ... }.not_to perform_at_least(...).ips" do
|
22
|
+
it "passes if the block does not perform more than 10K ips" do
|
23
|
+
expect {
|
24
|
+
'x' * 1024 * 1024 * 10
|
25
|
+
}.not_to perform_at_least(10_000).ips
|
26
|
+
end
|
27
|
+
|
28
|
+
it "fails if the block performs more than 10K ips" do
|
29
|
+
expect {
|
30
|
+
expect { 'x' * 1024 }.not_to perform_at_least(10_000).ips
|
31
|
+
}.to raise_error(/expected block not to perform at least 10000 i\/s, but performed \d+ \(± \d+%\) i\/s/)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe 'RSpec::Benchmark::TimingMatcher', '#perform_under' do
|
4
|
+
|
5
|
+
context "expect { ... }.to perfom_under(...).and_sample" do
|
6
|
+
it "passes if the block performs under threshold" do
|
7
|
+
expect {
|
8
|
+
'x' * 1024 * 10
|
9
|
+
}.to perform_under(0.006).sec.and_sample(10)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "fails if the block performs above threshold" do
|
13
|
+
expect {
|
14
|
+
expect {
|
15
|
+
'x' * 1024 * 1024 * 100
|
16
|
+
}.to perform_under(0.0001).and_sample(5)
|
17
|
+
}.to raise_error(/expected block to perform under 100 μs, but performed above \d+(\.\d+)? ([μmn]s|sec) \(± \d+(\.\d+)? ([μmn]s|sec)\)/)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "expect { ... }.not_to perform_under(...).and_sample" do
|
22
|
+
it "passes if the block does not perform under threshold" do
|
23
|
+
expect {
|
24
|
+
'x' * 1024 * 1024 * 10
|
25
|
+
}.to_not perform_under(0.001).and_sample(2)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "fails if the block perfoms under threshold" do
|
29
|
+
expect {
|
30
|
+
expect {
|
31
|
+
'x' * 1024 * 1024 * 10
|
32
|
+
}.to_not perform_under(1).and_sample(2)
|
33
|
+
}.to raise_error(/expected block to not perform under 1 sec, but performed \d+(\.\d+)? ([μmn]s|sec) \(± \d+(\.\d+)? ([μmn]s|sec)\) under/)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'threshold conversions' do
|
38
|
+
it "converts 1ms to sec" do
|
39
|
+
matcher = perform_under(1).ms
|
40
|
+
expect(matcher.threshold).to eq(0.001)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "converts 1000us to sec" do
|
44
|
+
matcher = perform_under(1000).us
|
45
|
+
expect(matcher.threshold).to eq(0.001)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "converts ns to sec" do
|
49
|
+
matcher = perform_under(100_000).ns
|
50
|
+
expect(matcher.threshold).to eq(0.0001)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'Run all specs'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc 'Run unit specs'
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run integration specs'
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Run performance specs'
|
23
|
+
RSpec::Core::RakeTask.new(:perf) do |task|
|
24
|
+
task.pattern = 'spec/performance{,/*/**}/*_spec.rb'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rescue LoadError
|
29
|
+
%w[spec spec:unit spec:integration spec:perf].each do |name|
|
30
|
+
task name do
|
31
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-benchmark
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Piotr Murach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: benchmark-perf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
- - <
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 4.0.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.0.0
|
44
|
+
- - <
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.0.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.5.0
|
54
|
+
- - <
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '2.0'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.5.0
|
64
|
+
- - <
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2.0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
description: Performance testing matchers for RSpec that provide simple way to specify
|
82
|
+
speed benchmark expectations
|
83
|
+
email:
|
84
|
+
- ''
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- .gitignore
|
90
|
+
- .rspec
|
91
|
+
- .travis.yml
|
92
|
+
- CHANGELOG.md
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- lib/rspec-benchmark.rb
|
98
|
+
- lib/rspec/benchmark.rb
|
99
|
+
- lib/rspec/benchmark/format_time.rb
|
100
|
+
- lib/rspec/benchmark/iteration_matcher.rb
|
101
|
+
- lib/rspec/benchmark/matchers.rb
|
102
|
+
- lib/rspec/benchmark/timing_matcher.rb
|
103
|
+
- lib/rspec/benchmark/version.rb
|
104
|
+
- rspec-benchmark.gemspec
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/unit/format_time_spec.rb
|
107
|
+
- spec/unit/perform_at_least_spec.rb
|
108
|
+
- spec/unit/perform_under_spec.rb
|
109
|
+
- tasks/coverage.rake
|
110
|
+
- tasks/spec.rake
|
111
|
+
homepage: ''
|
112
|
+
licenses:
|
113
|
+
- MIT
|
114
|
+
metadata: {}
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 2.0.3
|
132
|
+
signing_key:
|
133
|
+
specification_version: 4
|
134
|
+
summary: Performance testing matchers for RSpec
|
135
|
+
test_files:
|
136
|
+
- spec/spec_helper.rb
|
137
|
+
- spec/unit/format_time_spec.rb
|
138
|
+
- spec/unit/perform_at_least_spec.rb
|
139
|
+
- spec/unit/perform_under_spec.rb
|
140
|
+
has_rdoc:
|