rspec-specification-coverage
Allow specify coverage of files.
Why
Allow specify the way RSpec files cover the implementation.
Why such long name
There is a common misconception in the community that RSpec is mainly about testing - where it is mostly about specifying with ability to run that specification. Well written specification makes most documentation redundant - by reading the specification you should understand the implementation.
Usage
Install
Add following to your Gemfile:
group :test do
gem 'rspec-specification-coverage', '~> 0.1', require: false
end
And run:
bundle install
Basic
Ensures is respective spec file existing for implementation.
The following will ensure that spec/models/user_spec.rb
file exist:
require 'rspec/specification_coverage'
::RSpec.describe(::RSpec::SpecificationCoverage) do
subject(:file) { 'app/models/user.rb' }
it { is_expected.to(be_covered_with_specification) }
end
With Reflection
The following will ensure that in case there are git changes to
app/models/user.rb
, respective specification in
spec/models/user_spec.rb
also needs to be updated:
it { is_expected.to(be_covered_with_specification.with_reflection) }
Spec Bigger
The following will ensure that spec/models/user_spec.rb
file is bigger than app/models/user.rb
.
it { is_expected.to(be_covered_with_specification.spec_bigger) }
Mentioning Methods
The following will ensure that spec/models/user_spec.rb
file include method names from app/models/user.rb
.
it { is_expected.to(be_covered_with_specification.mentioning_methods) }
All
We can mix all above ways together:
it { is_expected.to(be_covered_with_specification.with_reflection.spec_bigger.mentioning_methods) }
Real Life Example
The following is a running example in one of my projects:
# frozen_string_literal: true
require 'rspec'
require 'rspec/specification_coverage'
::RSpec.describe(::RSpec::SpecificationCoverage) do
::Dir.glob('app/{helpers,models,channels,mailers}/**/*.rb').each do |a_file|
describe a_file do
subject(:file) { a_file }
it { is_expected.to(be_covered_with_specification.with_reflection.spec_bigger.mentioning_methods) }
end
end
::Dir.glob('app/jobs/**/*.rb').each do |a_file|
describe a_file do
subject(:file) { a_file }
it { is_expected.to(be_covered_with_specification.with_reflection) }
end
end
::Dir.glob('app/views/**/*.erb').each do |a_file|
describe a_file do
subject(:file) { a_file }
it { is_expected.to(be_covered_with_specification.with_reflection) }
end
end
::Dir.glob('lib/**/*.rb').each do |a_file|
describe a_file do
subject(:file) { a_file }
it { is_expected.to(be_covered_with_specification(type: :lib).with_reflection.mentioning_methods) }
end
end
::Dir.glob('app/controllers/**/*.rb').each do |a_file|
describe a_file do
subject(:file) { a_file }
it {
is_expected.to(
be_covered_with_specification(type: :requests).with_reflection.spec_bigger.mentioning_methods
)
}
it {
is_expected.to(
be_covered_with_specification(type: :routing).with_reflection.mentioning_methods
)
}
end
end
end
Development
We use TDD on Guard.
Setup
bash util/setup.sh
Check if overcommit is operational
bash util/overcommit_spec.sh
Run your TDD reactor
bundle exec guard