├── .rspec ├── lib ├── rspec_overview │ ├── version.rb │ ├── formatter_csv.rb │ ├── output │ │ ├── csv.rb │ │ └── markdown_table.rb │ ├── result.rb │ ├── collator.rb │ └── formatter.rb └── rspec_overview.rb ├── Gemfile ├── bin ├── console └── setup ├── spec ├── rspec_overview │ ├── version_spec.rb │ ├── output │ │ └── markdown_table_spec.rb │ ├── formatter_csv_spec.rb │ └── formatter_spec.rb ├── support │ ├── output_capturer.rb │ └── formatter_helpers.rb └── spec_helper.rb ├── .travis.yml ├── .gitignore ├── CHANGELOG.md ├── Rakefile ├── rspec_overview.gemspec ├── Gemfile.lock ├── LICENSE └── README.md /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | --format progress 4 | -------------------------------------------------------------------------------- /lib/rspec_overview/version.rb: -------------------------------------------------------------------------------- 1 | module RspecOverview 2 | VERSION = "0.3.0" 3 | end 4 | -------------------------------------------------------------------------------- /lib/rspec_overview.rb: -------------------------------------------------------------------------------- 1 | require "rspec_overview/version" 2 | 3 | module RspecOverview 4 | end 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in rspec_overview-formatter.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "rspec_overview/formatter" 5 | 6 | require "pry" 7 | Pry.start 8 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /spec/rspec_overview/version_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe RspecOverview do 2 | it "has a version number" do 3 | expect(RspecOverview::VERSION).not_to be nil 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.4 5 | - 2.5 6 | - 2.6 7 | - 2.7 8 | before_install: 9 | - gem update --system 10 | - gem install bundler 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | .ruby-version 10 | 11 | # rspec failure tracking 12 | .rspec_status 13 | -------------------------------------------------------------------------------- /spec/support/output_capturer.rb: -------------------------------------------------------------------------------- 1 | class OutputCapturer 2 | attr_reader :captures 3 | 4 | def initialize 5 | @captures = [] 6 | end 7 | 8 | def puts(obj) 9 | captures << obj 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.3.0 4 | - Switch default format to a markdown table 5 | - Drops `terminal-table` dependency 6 | - Fix missing require when using the CSV formatter 7 | 8 | ## v0.2.0 9 | - Add CSV format support 10 | 11 | ## v0.1.1 12 | - Tweak style of table titles 13 | 14 | ## v0.1.0 15 | - Initial release 16 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | RSpec::Core::RakeTask.new(:spec_with_formatters) do |t| 7 | t.rspec_opts = 8 | "--format RspecOverview::Formatter --format RspecOverview::FormatterCsv" 9 | end 10 | 11 | task default: [:spec, :spec_with_formatters] 12 | -------------------------------------------------------------------------------- /lib/rspec_overview/formatter_csv.rb: -------------------------------------------------------------------------------- 1 | require_relative "formatter" 2 | require_relative "output/csv" 3 | 4 | module RspecOverview 5 | class FormatterCsv < Formatter 6 | RSpec::Core::Formatters.register self, :dump_summary 7 | 8 | private 9 | 10 | def output_format 11 | RspecOverview::Output::Csv 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "rspec_overview" 3 | require "support/formatter_helpers" 4 | 5 | RSpec.configure do |config| 6 | config.example_status_persistence_file_path = ".rspec_status" 7 | config.disable_monkey_patching! 8 | 9 | config.expect_with :rspec do |c| 10 | c.syntax = :expect 11 | end 12 | 13 | config.mock_with :rspec do |mocks| 14 | mocks.verify_partial_doubles = true 15 | end 16 | 17 | config.order = :random 18 | Kernel.srand config.seed 19 | 20 | config.include FormatterHelpers, type: :formatter 21 | end 22 | -------------------------------------------------------------------------------- /lib/rspec_overview/output/csv.rb: -------------------------------------------------------------------------------- 1 | require "csv" 2 | 3 | module RspecOverview 4 | module Output 5 | class Csv 6 | def initialize(headings:, rows:) 7 | @headings = headings 8 | @rows = rows 9 | end 10 | 11 | def to_s 12 | CSV.generate(**csv_options, headers: headings) do |csv| 13 | rows.each { |row| csv << row } 14 | end 15 | end 16 | 17 | private 18 | 19 | attr_reader :headings, :rows 20 | 21 | def csv_options 22 | { write_headers: true, force_quotes: true } 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/rspec_overview/result.rb: -------------------------------------------------------------------------------- 1 | module RspecOverview 2 | class Result 3 | attr_reader :identifier 4 | attr_accessor :example_count, :duration_raw 5 | 6 | def initialize(identifier) 7 | @identifier = identifier 8 | @example_count = 0 9 | @duration_raw = 0.0 10 | end 11 | 12 | def avg_duration_seconds 13 | format_seconds(duration_raw / example_count) 14 | end 15 | 16 | def duration_seconds 17 | format_seconds(duration_raw) 18 | end 19 | 20 | private 21 | 22 | def format_seconds(duration) 23 | RSpec::Core::Formatters::Helpers.format_seconds(duration) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/support/formatter_helpers.rb: -------------------------------------------------------------------------------- 1 | module FormatterHelpers 2 | def example_double(metadata: {}, run_time: 0.0, file_path: "") 3 | execution_result = instance_double( 4 | RSpec::Core::Example::ExecutionResult, 5 | run_time: run_time, 6 | ) 7 | 8 | instance_double( 9 | RSpec::Core::Example, 10 | metadata: metadata, 11 | file_path: file_path, 12 | execution_result: execution_result, 13 | ) 14 | end 15 | 16 | def summary_double(examples:) 17 | instance_double( 18 | RSpec::Core::Notifications::SummaryNotification, 19 | examples: examples, 20 | ) 21 | end 22 | 23 | def dump_examples_as_summary(formatter, examples) 24 | formatter.dump_summary(summary_double(examples: examples)) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/rspec_overview/collator.rb: -------------------------------------------------------------------------------- 1 | require_relative "result" 2 | 3 | module RspecOverview 4 | class Collator 5 | def by_type_or_subfolder(examples) 6 | by_identifier(examples) do |example| 7 | example.metadata[:type] || extract_subfolder(example.file_path) 8 | end 9 | end 10 | 11 | def by_file_path(examples) 12 | by_identifier(examples) do |example| 13 | example.file_path 14 | end 15 | end 16 | 17 | private 18 | 19 | def by_identifier(examples) 20 | examples.each_with_object({}) do |example, results| 21 | identifier = yield(example) || "none" 22 | results[identifier] ||= Result.new(identifier) 23 | results[identifier].example_count += 1 24 | results[identifier].duration_raw += example.execution_result.run_time 25 | end.values 26 | end 27 | 28 | def extract_subfolder(file_path) 29 | file_path.slice(/.\/[^\/]+\/[^\/]+/) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /rspec_overview.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path("../lib", __FILE__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "rspec_overview/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "rspec_overview" 7 | spec.version = RspecOverview::VERSION 8 | spec.authors = ["Oli Peate"] 9 | spec.license = "MIT" 10 | 11 | spec.summary = "See an overview of your RSpec test suite" 12 | spec.homepage = "https://github.com/odlp/rspec_overview" 13 | 14 | spec.files = `git ls-files -z`.split("\x0").reject do |f| 15 | f.match(%r{^(test|spec|features)/}) 16 | end 17 | spec.bindir = "exe" 18 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency "rspec-core", "~> 3.0" 22 | 23 | spec.add_development_dependency "bundler", "~> 2.0" 24 | spec.add_development_dependency "pry-byebug", "~> 3.5" 25 | spec.add_development_dependency "rake", ">= 12" 26 | spec.add_development_dependency "rspec", "~> 3.7" 27 | end 28 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rspec_overview (0.3.0) 5 | rspec-core (~> 3.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | byebug (11.1.1) 11 | coderay (1.1.2) 12 | diff-lcs (1.3) 13 | method_source (0.9.2) 14 | pry (0.12.2) 15 | coderay (~> 1.1.0) 16 | method_source (~> 0.9.0) 17 | pry-byebug (3.8.0) 18 | byebug (~> 11.0) 19 | pry (~> 0.10) 20 | rake (13.0.1) 21 | rspec (3.9.0) 22 | rspec-core (~> 3.9.0) 23 | rspec-expectations (~> 3.9.0) 24 | rspec-mocks (~> 3.9.0) 25 | rspec-core (3.9.1) 26 | rspec-support (~> 3.9.1) 27 | rspec-expectations (3.9.0) 28 | diff-lcs (>= 1.2.0, < 2.0) 29 | rspec-support (~> 3.9.0) 30 | rspec-mocks (3.9.1) 31 | diff-lcs (>= 1.2.0, < 2.0) 32 | rspec-support (~> 3.9.0) 33 | rspec-support (3.9.2) 34 | 35 | PLATFORMS 36 | ruby 37 | 38 | DEPENDENCIES 39 | bundler (~> 2.0) 40 | pry-byebug (~> 3.5) 41 | rake (>= 12) 42 | rspec (~> 3.7) 43 | rspec_overview! 44 | 45 | BUNDLED WITH 46 | 2.1.2 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Oliver Peate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /spec/rspec_overview/output/markdown_table_spec.rb: -------------------------------------------------------------------------------- 1 | require "rspec_overview/output/markdown_table" 2 | 3 | RSpec.describe RspecOverview::Output::MarkdownTable do 4 | it "generates a markdown table" do 5 | table = described_class.new( 6 | headings: ["Heading", "Longer Heading", "Short"], 7 | rows: [ 8 | ["Longer row 1A", "Row 1B", "1C"], 9 | ["Row 2A", "Row 2B", "2C"], 10 | ] 11 | ) 12 | 13 | expect(table.to_s).to eq <<~TABLE 14 | | Heading | Longer Heading | Short | 15 | |---------------|----------------|-------| 16 | | Longer row 1A | Row 1B | 1C | 17 | | Row 2A | Row 2B | 2C | 18 | TABLE 19 | end 20 | 21 | it "handles nil cell values" do 22 | table = described_class.new( 23 | headings: ["Heading", "Optional"], 24 | rows: [ 25 | ["1A", "1B"], 26 | ["2A", nil], 27 | ["3A", "3B"], 28 | ] 29 | ) 30 | 31 | expect(table.to_s).to eq <<~TABLE 32 | | Heading | Optional | 33 | |---------|----------| 34 | | 1A | 1B | 35 | | 2A | | 36 | | 3A | 3B | 37 | TABLE 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/rspec_overview/formatter.rb: -------------------------------------------------------------------------------- 1 | require "rspec/core" 2 | require_relative "output/markdown_table" 3 | require_relative "collator" 4 | 5 | module RspecOverview 6 | class Formatter 7 | RSpec::Core::Formatters.register self, :dump_summary 8 | 9 | def initialize(output) 10 | @output = output 11 | end 12 | 13 | def dump_summary(summary) 14 | examples = summary.examples 15 | 16 | summarize_by("Type or Subfolder", collator.by_type_or_subfolder(examples)) 17 | summarize_by("File", collator.by_file_path(examples)) 18 | end 19 | 20 | private 21 | 22 | attr_reader :output 23 | 24 | def summarize_by(identifier, results) 25 | sorted_results = results.sort_by(&:duration_raw).reverse_each 26 | 27 | headings, attributes = { 28 | identifier => :identifier, 29 | "Example count" => :example_count, 30 | "Duration (s)" => :duration_seconds, 31 | "Average per example (s)" => :avg_duration_seconds, 32 | }.to_a.transpose 33 | 34 | output_body = output_format.new( 35 | headings: headings, 36 | rows: pluck_attributes(sorted_results, attributes), 37 | ) 38 | 39 | output.puts "\n# Summary by #{identifier}\n\n" 40 | output.puts output_body 41 | output.puts "\n" 42 | end 43 | 44 | def pluck_attributes(results, attributes) 45 | results.map do |result| 46 | attributes.map { |attribute| result.public_send(attribute) } 47 | end 48 | end 49 | 50 | def output_format 51 | RspecOverview::Output::MarkdownTable 52 | end 53 | 54 | def collator 55 | Collator.new 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/rspec_overview/output/markdown_table.rb: -------------------------------------------------------------------------------- 1 | require "matrix" 2 | 3 | module RspecOverview 4 | module Output 5 | class MarkdownTable 6 | BORDER_SEPERATOR = "|".freeze 7 | NOT_BORDER_SEPERATOR = /[^#{BORDER_SEPERATOR}]/ 8 | HEADING_SEPERATOR = "-".freeze 9 | 10 | def initialize(headings:, rows:) 11 | @matrix = Matrix.rows([headings] + rows) 12 | end 13 | 14 | def to_s 15 | render_table 16 | end 17 | 18 | def column(index) 19 | matrix.column(index).to_a 20 | end 21 | 22 | private 23 | 24 | attr_reader :matrix 25 | 26 | def render_table 27 | heading_row = render_row(header_data) 28 | heading_divider = create_heading_divider(heading_row) 29 | body_rows = render_rows(body_data).join("\n") 30 | 31 | <<~OUTPUT 32 | #{heading_row} 33 | #{heading_divider} 34 | #{body_rows} 35 | OUTPUT 36 | end 37 | 38 | def header_data 39 | matrix.row_vectors[0] 40 | end 41 | 42 | def body_data 43 | matrix.row_vectors[1..-1] 44 | end 45 | 46 | def render_rows(data_rows) 47 | data_rows.map(&method(:render_row)) 48 | end 49 | 50 | def render_row(data_row) 51 | table_row = [BORDER_SEPERATOR] 52 | 53 | data_row.each_with_index do |value, column_index| 54 | table_row << " #{pad_value(value, column_index)} #{BORDER_SEPERATOR}" 55 | end 56 | 57 | table_row.join 58 | end 59 | 60 | def create_heading_divider(line) 61 | line.gsub(NOT_BORDER_SEPERATOR, HEADING_SEPERATOR) 62 | end 63 | 64 | def pad_value(value, column_index) 65 | column_width = width_of_column(column_index) 66 | value.to_s.ljust(column_width, " ") 67 | end 68 | 69 | def width_of_column(index) 70 | column(index).max_by{ |value| value.to_s.length }.length 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/rspec_overview/formatter_csv_spec.rb: -------------------------------------------------------------------------------- 1 | require "csv" 2 | require "rspec_overview/formatter_csv" 3 | require "support/output_capturer" 4 | 5 | RSpec.describe RspecOverview::FormatterCsv, type: :formatter do 6 | let(:output) { OutputCapturer.new } 7 | subject { described_class.new(output) } 8 | 9 | describe "summary by spec type" do 10 | it "groups examples by type and sums the execution run time" do 11 | examples = [ 12 | example_double(metadata: { type: "feature" }, run_time: 1.5), 13 | example_double(metadata: { type: "feature" }, run_time: 0.5), 14 | example_double(metadata: { type: "model" }, run_time: 1.5), 15 | ] 16 | 17 | dump_examples_as_summary(subject, examples) 18 | 19 | expect(output.captures[0]).to include "# Summary by Type or Subfolder" 20 | 21 | csv = CSV.parse(output.captures[1].to_s, headers: true) 22 | 23 | expect(csv.by_col["Type or Subfolder"]). 24 | to eq ["feature", "model"] 25 | 26 | expect(csv.by_col["Example count"]). 27 | to eq ["2", "1"] 28 | 29 | expect(csv.by_col["Duration (s)"]). 30 | to eq ["2", "1.5"] 31 | 32 | expect(csv.by_col["Average per example (s)"]). 33 | to eq ["1", "1.5"] 34 | end 35 | end 36 | 37 | describe "summary by file" do 38 | it "groups examples by file path and sums the execution run time" do 39 | examples = [ 40 | example_double(file_path: "./spec/foo/foo_spec.rb", run_time: 1.0), 41 | example_double(file_path: "./spec/foo/foo_spec.rb", run_time: 1.5), 42 | example_double(file_path: "./spec/baz/baz_spec.rb", run_time: 1.0), 43 | ] 44 | 45 | dump_examples_as_summary(subject, examples) 46 | 47 | expect(output.captures[3]).to include "# Summary by File" 48 | 49 | csv = CSV.parse(output.captures[4].to_s, headers: true) 50 | 51 | expect(csv.by_col["File"]). 52 | to eq ["./spec/foo/foo_spec.rb", "./spec/baz/baz_spec.rb"] 53 | 54 | expect(csv.by_col["Example count"]). 55 | to eq ["2", "1"] 56 | 57 | expect(csv.by_col["Duration (s)"]). 58 | to eq ["2.5", "1"] 59 | 60 | expect(csv.by_col["Average per example (s)"]). 61 | to eq ["1.25", "1"] 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/rspec_overview/formatter_spec.rb: -------------------------------------------------------------------------------- 1 | require "support/output_capturer" 2 | require "rspec_overview/formatter" 3 | 4 | RSpec.describe RspecOverview::Formatter, type: :formatter do 5 | include FormatterHelpers 6 | 7 | let(:output) { OutputCapturer.new } 8 | subject { described_class.new(output) } 9 | 10 | describe "summary by spec type" do 11 | it "groups examples by type and sums the execution run time" do 12 | examples = [ 13 | example_double(metadata: { type: "feature" }, run_time: 1.5), 14 | example_double(metadata: { type: "feature" }, run_time: 0.5), 15 | example_double(metadata: { type: "model" }, run_time: 1.5), 16 | ] 17 | 18 | dump_examples_as_summary(subject, examples) 19 | 20 | expect(output.captures.first).to include "# Summary by Type or Subfolder" 21 | 22 | table = output_tables.first 23 | 24 | expect(table.column(0)).to eq ["Type or Subfolder", "feature", "model"] 25 | expect(table.column(1)).to eq ["Example count", 2, 1] 26 | expect(table.column(2)).to eq ["Duration (s)", "2", "1.5"] 27 | expect(table.column(3)).to eq ["Average per example (s)", "1", "1.5"] 28 | end 29 | 30 | it "uses the spec subfolder when a meta-type isn't available" do 31 | examples = [ 32 | example_double(file_path: "./spec/foo/foo_spec.rb", run_time: 1.0), 33 | example_double(file_path: "./spec/foo/bar/bar_spec.rb", run_time: 1.0), 34 | example_double(file_path: "./spec/baz/baz_spec.rb", run_time: 1.0), 35 | ] 36 | 37 | dump_examples_as_summary(subject, examples) 38 | table = output_tables.first 39 | 40 | expect(table.column(0)). 41 | to eq ["Type or Subfolder", "./spec/foo", "./spec/baz"] 42 | 43 | expect(table.column(1)).to eq ["Example count", 2, 1] 44 | expect(table.column(2)).to eq ["Duration (s)", "2", "1"] 45 | expect(table.column(3)).to eq ["Average per example (s)", "1", "1"] 46 | end 47 | end 48 | 49 | describe "summary by file" do 50 | it "groups examples by file path and sums the execution run time" do 51 | examples = [ 52 | example_double(file_path: "./spec/foo/foo_spec.rb", run_time: 1.0), 53 | example_double(file_path: "./spec/foo/foo_spec.rb", run_time: 1.5), 54 | example_double(file_path: "./spec/baz/baz_spec.rb", run_time: 1.0), 55 | ] 56 | 57 | dump_examples_as_summary(subject, examples) 58 | 59 | expect(output.captures[3]).to include "# Summary by File" 60 | 61 | table = output_tables.last 62 | 63 | expect(table.column(0)). 64 | to eq ["File", "./spec/foo/foo_spec.rb", "./spec/baz/baz_spec.rb"] 65 | 66 | expect(table.column(1)).to eq ["Example count", 2, 1] 67 | expect(table.column(2)).to eq ["Duration (s)", "2.5", "1"] 68 | expect(table.column(3)).to eq ["Average per example (s)", "1.25", "1"] 69 | end 70 | end 71 | 72 | private 73 | 74 | def output_tables 75 | output.captures.select do |capture| 76 | capture.respond_to?(:column) 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RspecOverview 2 | 3 | [![Build Status](https://travis-ci.org/odlp/rspec_overview.svg?branch=master)](https://travis-ci.org/odlp/rspec_overview) 4 | 5 | Take `RspecOverview::Formatter` for a spin when you're new to a project and need 6 | an overview: 7 | 8 | - How are the tests structured? 9 | - How many tests are there by type (feature, model, controller)? 10 | - Which tests are taking the most time? 11 | 12 | ## Usage 13 | 14 | Add the gem to your `Gemfile` and run `bundle`: 15 | 16 | ```ruby 17 | group :test do 18 | gem "rspec_overview" 19 | end 20 | ``` 21 | 22 | You can use the overview formatter standalone, or mix & match with other 23 | formatters: 24 | 25 | ```sh 26 | # With the progress formatter: 27 | bundle exec rspec --format progress --format RspecOverview::Formatter 28 | 29 | # With the documentation formatter: 30 | bundle exec rspec --format documentation --format RspecOverview::Formatter 31 | ``` 32 | 33 | ### CSV format 34 | 35 | You can also produce a CSV for further analysis: 36 | 37 | ```sh 38 | bundle exec rspec --format RspecOverview::FormatterCsv --out overview.csv 39 | ``` 40 | 41 | ## Example output 42 | 43 | Run against [thoughtbot/administrate][administrate]: 44 | 45 | [administrate]: https://github.com/thoughtbot/administrate 46 | 47 | ``` 48 | Randomized with seed 16132 49 | ................................................................................ 50 | ................................................................................ 51 | ................................................................................ 52 | ...................................................................... 53 | 54 | Finished in 15.03 seconds (files took 6.02 seconds to load) 55 | 310 examples, 0 failures 56 | 57 | # Summary by Type or Subfolder 58 | 59 | | Type or Subfolder | Example count | Duration (s) | Average per example (s) | 60 | |---------------------|---------------|--------------|-------------------------| 61 | | feature | 72 | 9.28 | 0.12889 | 62 | | generator | 65 | 1.83 | 0.0282 | 63 | | controller | 32 | 1.69 | 0.05293 | 64 | | view | 14 | 0.68246 | 0.04875 | 65 | | ./spec/i18n_spec.rb | 2 | 0.58921 | 0.2946 | 66 | | ./spec/lib | 79 | 0.33908 | 0.00429 | 67 | | model | 28 | 0.29078 | 0.01038 | 68 | | ./spec/administrate | 5 | 0.03813 | 0.00763 | 69 | | ./spec/dashboards | 9 | 0.024 | 0.00267 | 70 | | helper | 4 | 0.01062 | 0.00265 | 71 | 72 | 73 | # Summary by File 74 | 75 | | File | Example count | Duration (s) | Average per example (s) | 76 | |-------------------------------------------------------------|---------------|--------------|-------------------------| 77 | | ./spec/features/index_page_spec.rb | 11 | 2.76 | 0.25125 | 78 | | ./spec/controllers/admin/customers_controller_spec.rb | 15 | 1.11 | 0.07432 | 79 | | ./spec/features/form_errors_spec.rb | 2 | 1.1 | 0.54813 | 80 | | ./spec/generators/dashboard_generator_spec.rb | 20 | 1.06 | 0.05293 | 81 | | ./spec/features/orders_form_spec.rb | 7 | 1.01 | 0.14472 | 82 | | ./spec/features/show_page_spec.rb | 10 | 0.67528 | 0.06753 | 83 | | ./spec/i18n_spec.rb | 2 | 0.58921 | 0.2946 | 84 | | ./spec/features/search_spec.rb | 3 | 0.57751 | 0.1925 | 85 | | ./spec/features/orders_index_spec.rb | 6 | 0.57129 | 0.09521 | 86 | | ./spec/features/products_index_spec.rb | 4 | 0.54049 | 0.13512 | 87 | | | | | | 88 | 89 | Randomized with seed 40301 90 | ``` 91 | --------------------------------------------------------------------------------