rspec-rotten 0.0.2
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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +90 -0
- data/Rakefile +2 -0
- data/lib/rspec/rotten/configuration.rb +15 -0
- data/lib/rspec/rotten/example_store.rb +64 -0
- data/lib/rspec/rotten/formatters/initial_report_formatter.rb +38 -0
- data/lib/rspec/rotten/formatters/rotten_report_formatter.rb +61 -0
- data/lib/rspec/rotten/initial_report_creator.rb +28 -0
- data/lib/rspec/rotten/version.rb +5 -0
- data/lib/rspec/rotten.rb +6 -0
- data/rspec-rotten.gemspec +26 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8baf4e11c797e50c69cd91a3f187f3822dbfb7d9
|
4
|
+
data.tar.gz: 1f1eb1f40760ccd5145abe0021ee322b2cac70c0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: baed89376e63e2dde843531bd0f389b31483965dc17b68eb5e3ccab4c583cbb55cf4f4dc3b4d0738036b80f8829802fe1c7b38856c33a44e88f4a39dac2e0662
|
7
|
+
data.tar.gz: b47adb41ae5f03bda358ad5781d71991a6e93f9f2af3e988ad3f8c91a56ec5009bad6b993e2022eba787fc6042751b2416d1d7a1a39174c4e43c21062125018a
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Simon Bagreev
|
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,90 @@
|
|
1
|
+
# Rspec::Rotten
|
2
|
+
|
3
|
+
According to [pronounced James O Coplien essay](http://www.rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf),
|
4
|
+
most unit tests are waste. Particulary, James says:
|
5
|
+
|
6
|
+
>If you want to reduce your test mass, the number one
|
7
|
+
>thing you should do is look at the tests that have never
|
8
|
+
>failed in a year and consider throwing them away. They are
|
9
|
+
>producing no information for you — or at least very little
|
10
|
+
>information. The value of the information they produce may
|
11
|
+
>not be worth the expense of maintaining and running the
|
12
|
+
>tests. This is the first set of tests to throw away — whether
|
13
|
+
>they are unit tests, integration tests, or system tests.
|
14
|
+
|
15
|
+
This gem lets you track tests that haven't failed for given period of time,
|
16
|
+
and prompts you to "reduce test mass" by removing them.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
### Step 1
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'rspec-rotten'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install rspec-rotten
|
35
|
+
|
36
|
+
### Step 2
|
37
|
+
|
38
|
+
Create initializer and specify path to a file that will be storing stats of your
|
39
|
+
test runs, and, most importantly, _time period after which specs will be considered
|
40
|
+
"rotten"_, given they didn't change status(failed/passed/became pending):
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# config/initializers/rspec-rotten.rb
|
44
|
+
Rspec::Rotten::Configuration.configure do |config|
|
45
|
+
config.results_file = Rails.root.join('output.json')
|
46
|
+
config.time_to_rotten = 1.year
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Also add this line to RSpec config in spec_helper/rails_helper:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# spec/rails_helper.rb
|
54
|
+
RSpec.configure do |config|
|
55
|
+
...
|
56
|
+
config.add_formatter(Rspec::Rotten::Formatters::RottenReportFormatter)
|
57
|
+
...
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
### Step 3
|
62
|
+
|
63
|
+
Run **the entire suite** to genreate initial spec report:
|
64
|
+
|
65
|
+
```
|
66
|
+
rake spec
|
67
|
+
```
|
68
|
+
_**NOTE:**_ This will create the report that will reflect the status of your specs,
|
69
|
+
and will be updated every time you run specs. It's recommended to check this file
|
70
|
+
under source control, to share this data with your co-workers.
|
71
|
+
|
72
|
+
## VIOLA!
|
73
|
+
|
74
|
+
Now, every time you run specs, you will get an annoying message _if you have
|
75
|
+
"rotten" specs_ (it's easy to turn OFF by commenting out Formatter in step 2).
|
76
|
+
|
77
|
+
## TODO
|
78
|
+
|
79
|
+
* create rake task / installer to generate initial report
|
80
|
+
* notify only about the examples currently executed (not the whole suite)
|
81
|
+
* allow user to use Formatter from CLI like `rspec --format RottenFormatter spec/`
|
82
|
+
* give user a chance to only track unit/integration/acceptance specs
|
83
|
+
|
84
|
+
## Contributions welcomed
|
85
|
+
|
86
|
+
1. Fork it ( https://github.com/[my-github-username]/rspec-rotten/fork )
|
87
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
88
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
89
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
90
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'time'
|
3
|
+
require 'rspec/core/formatters/console_codes'
|
4
|
+
require 'rspec/rotten/configuration'
|
5
|
+
|
6
|
+
module Rspec
|
7
|
+
module Rotten
|
8
|
+
class ExampleStore
|
9
|
+
# 1 year duration when AS is not available
|
10
|
+
ROTTEN_DURATION = Time.parse("2016-01-01") - Time.parse("2015-01-01")
|
11
|
+
|
12
|
+
attr_accessor :file_path, :records
|
13
|
+
|
14
|
+
def initialize()
|
15
|
+
@file_path = Rspec::Rotten::Configuration.results_file
|
16
|
+
@records = File.exists?(@file_path) ? JSON.parse(read_example_data) : []
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(example)
|
20
|
+
@records.find{ |x| x['id'] == example.id }
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete(example)
|
24
|
+
@records.delete example
|
25
|
+
end
|
26
|
+
|
27
|
+
def save
|
28
|
+
f = File.open(@file_path,"w")
|
29
|
+
f.truncate(0)
|
30
|
+
f.write(@records.to_json)
|
31
|
+
f.close
|
32
|
+
end
|
33
|
+
|
34
|
+
# use config for date
|
35
|
+
def rotten
|
36
|
+
rotten_duration = Rspec::Rotten::Configuration.time_to_rotten || ROTTEN_TIME
|
37
|
+
@rotten ||= @records.select {|x| !x['date'].nil? && x['date'] < Time.now() - rotten_duration }
|
38
|
+
end
|
39
|
+
|
40
|
+
def notify_rotten
|
41
|
+
if @rotten.any?
|
42
|
+
@message = %Q{
|
43
|
+
\n\nYou have #{@rotten.count} specs that haven't failed for extended period of time.\n\t
|
44
|
+
\n\nYou may want to consider removing them:\n\t
|
45
|
+
#{@records.map {|example| example['description'] + " - " + example['location'] }.join("\n\t")}
|
46
|
+
\n
|
47
|
+
}
|
48
|
+
RSpec::Core::Formatters::ConsoleCodes.wrap(@message, :pending)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def read_example_data
|
55
|
+
if File.exists? @file_path
|
56
|
+
f = File.open(@file_path, 'r')
|
57
|
+
data = f.read
|
58
|
+
f.close
|
59
|
+
data
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rspec/core/formatters'
|
2
|
+
module Rspec
|
3
|
+
module Rotten
|
4
|
+
module Formatters
|
5
|
+
class InitialReportFormatter
|
6
|
+
RSpec::Core::Formatters.register self, :example_passed, :example_failed, :example_pending, :close
|
7
|
+
|
8
|
+
def initialize(output)
|
9
|
+
@output = output
|
10
|
+
@arr = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def example_passed(notification)
|
14
|
+
@arr << example_data(notification.example, :passed)
|
15
|
+
end
|
16
|
+
|
17
|
+
def example_failed(notification)
|
18
|
+
@arr << example_data(notification.example, :failed)
|
19
|
+
end
|
20
|
+
|
21
|
+
def example_pending(notification)
|
22
|
+
@arr << example_data(notification.example, :pending)
|
23
|
+
end
|
24
|
+
|
25
|
+
def close(notification)
|
26
|
+
@output.write @arr.to_json
|
27
|
+
@output.close if IO === @output && @output != $stdout
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def example_data(example, status)
|
33
|
+
{ id: example.id, state: status, date: Time.now, location: example.location, description: example.description }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rspec/core/formatters'
|
2
|
+
require 'json'
|
3
|
+
require 'rspec/rotten/example_store'
|
4
|
+
|
5
|
+
module Rspec
|
6
|
+
module Rotten
|
7
|
+
module Formatters
|
8
|
+
class RottenReportFormatter
|
9
|
+
RSpec::Core::Formatters.register self, :example_passed, :example_failed, :example_pending, :close
|
10
|
+
|
11
|
+
def initialize(output)
|
12
|
+
@output = output
|
13
|
+
@store = ExampleStore.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def example_passed(notification)
|
17
|
+
record = @store.find(notification.example)
|
18
|
+
if record && record['state'] != 'passed'
|
19
|
+
@store.delete record
|
20
|
+
@store.records << example_data(notification.example, :passed)
|
21
|
+
elsif record.nil?
|
22
|
+
@store.records << example_data(notification.example, :passed)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def example_failed(notification)
|
27
|
+
record = @store.find(notification.example)
|
28
|
+
if record && record['state'] != 'failed'
|
29
|
+
@store.delete record
|
30
|
+
@store.records << example_data(notification.example, :failed)
|
31
|
+
elsif record.nil?
|
32
|
+
@store.records << example_data(notification.example, :failed)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def example_pending(notification)
|
37
|
+
record = @store.find(notification.example)
|
38
|
+
if record && record['state'] != 'pending'
|
39
|
+
@store.delete record
|
40
|
+
@store.records << example_data(notification.example, :pending)
|
41
|
+
elsif record.nil?
|
42
|
+
@store.records << example_data(notification.example, :pending)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# write into a file
|
47
|
+
# generate a report into STDOUT what specs haven't failed for a year
|
48
|
+
def close(notification)
|
49
|
+
@store.save
|
50
|
+
@output << @store.notify_rotten if @store.rotten.any?
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def example_data(example, status)
|
56
|
+
{ id: example.id, state: status, date: Time.now, location: example.location, description: example.description }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rspec/rotten/formatters/initial_report_formatter'
|
3
|
+
|
4
|
+
module Rspec
|
5
|
+
module Rotten
|
6
|
+
class InitialReportCreator
|
7
|
+
def self.create_report
|
8
|
+
unless File.exist?(Rspec::Rotten::Configuration.results_file)
|
9
|
+
config = RSpec.configuration
|
10
|
+
|
11
|
+
formatter = Rspec::Rotten::Formatters::InitialReportFormatter.new(Rspec::Rotten::Configuration.results_file)
|
12
|
+
|
13
|
+
reporter = RSpec::Core::Reporter.new(config)
|
14
|
+
config.instance_variable_set(:@reporter, reporter)
|
15
|
+
|
16
|
+
# internal hack
|
17
|
+
# api may not be stable, make sure lock down Rspec version
|
18
|
+
loader = config.send(:formatter_loader)
|
19
|
+
notifications = loader.send(:notifications_for, Rspec::Rotten::Formatters::InitialReportFormatter)
|
20
|
+
|
21
|
+
reporter.register_listener(formatter, *notifications)
|
22
|
+
|
23
|
+
RSpec::Core::Runner.run([config.default_path])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rspec/rotten.rb
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
require "rspec/rotten/version"
|
2
|
+
require "rspec/rotten/example_store"
|
3
|
+
require "rspec/rotten/configuration"
|
4
|
+
require "rspec/rotten/initial_report_creator"
|
5
|
+
require "rspec/rotten/formatters/initial_report_formatter"
|
6
|
+
require "rspec/rotten/formatters/rotten_report_formatter"
|
@@ -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/rotten/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rspec-rotten"
|
8
|
+
spec.version = Rspec::Rotten::VERSION
|
9
|
+
spec.authors = ["Simon Bagreev"]
|
10
|
+
spec.email = ["sbagreev@gmail.com"]
|
11
|
+
spec.summary = %q{Detects rotten specs}
|
12
|
+
spec.description = %q{Tracks the specs that haven't changed status
|
13
|
+
(failed/passed/pending) for given period of time, and
|
14
|
+
signals you to remove them}
|
15
|
+
spec.homepage = ""
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "rspec", "~> 3.0"
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-rotten
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Bagreev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description: |-
|
56
|
+
Tracks the specs that haven't changed status
|
57
|
+
(failed/passed/pending) for given period of time, and
|
58
|
+
signals you to remove them
|
59
|
+
email:
|
60
|
+
- sbagreev@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- lib/rspec/rotten.rb
|
71
|
+
- lib/rspec/rotten/configuration.rb
|
72
|
+
- lib/rspec/rotten/example_store.rb
|
73
|
+
- lib/rspec/rotten/formatters/initial_report_formatter.rb
|
74
|
+
- lib/rspec/rotten/formatters/rotten_report_formatter.rb
|
75
|
+
- lib/rspec/rotten/initial_report_creator.rb
|
76
|
+
- lib/rspec/rotten/version.rb
|
77
|
+
- rspec-rotten.gemspec
|
78
|
+
homepage: ''
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.4.8
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Detects rotten specs
|
102
|
+
test_files: []
|