20

I decided to try using simplecov gem, and I think it's a cool tool, but I have one problem:

I have a model User, and I have user_spec.rb which contains test cases, but simplecov shows 0% coverage of this model. And it shows 100% coverage for other models, which is true. I don't understand what's the issue with the User model.

class User < ActiveRecord::Base

  extend Enumerize

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  STATUS_ACTIVE = :active
  STATUS_BANNED = :banned

  enumerize :status, in: [STATUS_ACTIVE, STATUS_BANNED], default: STATUS_ACTIVE

  with_options inverse_of: :user, dependent: :destroy do
    has_one :profile
    has_many :articles
  end

  before_create :build_default_profile

  private

  def build_default_profile
    build_profile
  end

end

user_spec.rb

 require 'rails_helper'
    
    RSpec.describe User, type: :model do
    
      describe '#validations' do
        it { should have_one(:profile).dependent(:destroy) }
    
        it { should validate_presence_of(:email) }
        it { should validate_presence_of(:password) }
        it { should validate_confirmation_of(:password) }
    
        it { should enumerize(:status).in(User::STATUS_ACTIVE, User::STATUS_BANNED).with_default(User::STATUS_ACTIVE) }
    
        #TODO other devise validations
      end
    
      describe '#callbacks' do
        it 'creates profile after_create' do
          user = build(:user)
          expect(user.profile).to be_nil
          user.save
          expect(user.profile).to be_a(Profile)
        end
    
        it 'must not create profile after update' do
          user = create(:user)
          profile = user.profile
          user.email = Faker::Internet.email
          user.save
          expect(profile.id).to eq(Profile.find_by(user_id: user.id).id)
        end
      end
    
    end

coverage

File                 % covered Lines Relevant Lines Lines covered   Lines missed    Avg. Hits / Line
app/models/user.rb      0.0 %   28  28  0   28  0.0
app/models/admin.rb     100.0 % 3   1   1   0   1.0
app/models/article.rb   100.0 % 32  19  19  0   5.8
app/models/profile.rb   100.0 % 13  6   6   0   1.0
michaelrbock
  • 1,160
  • 1
  • 11
  • 20
eugene_trebin
  • 1,485
  • 1
  • 16
  • 29
  • what command do you use to run the spec? Are you sure user_spec.rb is being run as well - if you put `binding.pry` or `puts "it works"` inside '#callbacks' test - would it stop/print the message? – basiam Feb 18 '16 at 11:20
  • Yes, i'm sure, i used command rspec in terminal – eugene_trebin Feb 19 '16 at 14:19
  • I'm seeing this issue as well. I'm using Devise, and it looks like you are too. I wonder if it is interfering somehow. I'm on Devise 3.5.2, how about you? Version of Simplecov is 0.11.1. This issue just started happening for me. My User model has extensive tests. – stephen.hanson Feb 29 '16 at 19:03
  • @stephen.hanson I have hit this issue of 100& for all but 0% for User. The only hypothesis I can formulate is `devise` and the fact that the User class is both the object of and the driver of access. Have you resolved this? – Jerome Nov 26 '21 at 15:29
  • 1
    @Jerome this was quite a while ago, but if I remember correctly, I think the issue for me was due to Spring. If I ran `bundle exec rspec` instead of using the Spring binstub, I think the coverage was reported correctly. – stephen.hanson Nov 30 '21 at 16:43
  • @stephen.hanson Good for prodding your memory there! Unfortunately rspec is *not* intalled on this application (and not in `Gemfile.lock` . just minitest... I have meanwhile found that `bundle exec rake test test/models`( *not* `rails` ) gets the coverage data percolating to the html pages (but at the cost of running the entire test suite. – Jerome Dec 01 '21 at 07:58

8 Answers8

15

Make sure that you are starting SimpleCov correctly. In your case,

Load and launch SimpleCov at the very top of your rails_helper.rb

See more: https://github.com/colszowka/simplecov#getting-started

Luan James
  • 221
  • 1
  • 5
10

It happens with me only when I use spring, actually when I use rspec binstub generated by spring-commands-rspec gem. Try to stop spring with command spring stop and run specs again with rspec spec.

8

I have a similar issue. I have the current simplecov 0.17.1.

I'm using Rails 6 with the default setup (Minitest and Spring, no rspec), I run my tests with rails test.

I have try all the other answers without success.

simplecov may be buggy: https://github.com/colszowka/simplecov/issues/671

I'm trying alternative like fastcov

edit1
fastcov seems to be a ligthen copy of simplecov, not mature at all. It's not released yet! Is their any alternative to simplecov?!

edit2
I manage to make it work by adding to the top of bin/rails

#!/usr/bin/env ruby
if ENV['RAILS_ENV'] == 'test'
  require 'simplecov'
  SimpleCov.start 'rails'
  puts "required simplecov"
end
# ...

AND in test_helper.rb, I set parallelize(workers: 1)

# test/test_helper.rb
require 'simplecov'
SimpleCov.start 'rails'

ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'

class ActiveSupport::TestCase
  parallelize(workers: 1)
  fixtures :all
end

I run tests with the command RAILS_ENV=test rails test

  • 4
    Thanks man! I had the same setup with Rails 6, Minitest & Spring and face the same issue. Always 0% covered. What really solved it for me was your hint about setting the parallelize workers to 1. Since than it's running like expected! – Robert Reiz May 20 '20 at 16:18
  • 2
    simply disabling `parallelize` seems to be the workaround until simplecov supports it https://github.com/colszowka/simplecov/issues/718 – AxelTheGerman Jun 21 '20 at 22:15
4

You have to create an initilizer like this:

config/initializers/simplecov.rb

if ENV['RAILS_ENV'] == 'test'
  require 'simplecov'
  SimpleCov.start 'rails'
  puts "required simplecov"
end
2

I had the same problem and just found the answer here: https://github.com/colszowka/simplecov/issues/82

The require should be happening before loading anything else. In my case I had:

require simplecov SimpleCov.start 'rails'

after:

require File.expand_path('../../config/environment', __FILE__)

which probably made the devise modules not being loaded. As soon as I moved the "require simplecov" and "simplecov.start" to the very beginning of rails_helper, it worked as expected.

duromano
  • 21
  • 1
1

The metric that simplecov displays is the number of lines that get called in the process of running test cases. For example if I had:

class Test
  def method
    'Response'
  end
end

RSpec.describe Test, type: :model do
  context '#method' do
    let(:test) { Test.new }

    it 'returns response' do
      expect(test.method).to eq('Response')
    end
  end
end

simplecov will show 100% coverage because it is hitting every single line in the Test class when I run my specs. In the case of your user class, your specs don't actually invoke any lines in the user class because you don't have any relevant lines (it isn't considering your private method to be relevant).

I wouldn't worry about the 0% coverage for your user model as the tests you have seem pretty comprehensive.

Spacepotato
  • 146
  • 10
  • thanks for description, but it's very strange, model Admin is a descendant of model User, user_spec.rb and admin_spec.rb have almost the same code, but simplecov show 100% coverave of admin.rb and 0% of user.rb – eugene_trebin Feb 18 '16 at 10:52
  • Hmm that is a bit odd. Do you have any additional methods in your admin model? – Spacepotato Feb 18 '16 at 13:48
  • no, Admin < User; end; and i copied code from user_spec.rb to admin_spec.rb – eugene_trebin Feb 19 '16 at 14:21
  • Very odd indeed. As you can see in the simplecov results it is considering admin.rb to have 1 relevant line which makes me think that it is considering build_default_profile to be relevant only in the admin class. Try blocking it out using :novoc: (before and after the method definition) and see if that changes the results. – Spacepotato Feb 19 '16 at 14:28
1

I was seeing the same issue, and I think it has something to do with Spring rspec binstubs. I'm using the spring-commands-rspec gem and have a binstub for rspec in bin/spring. After creating that binstub, my Simplecov test coverage calculations went down by 10% and showed that my User model had 0% coverage. When I deleted (or renaming works too) the bin/spring script and re-ran rspec, my coverage was back up.

Are you using spring-commands-rspec or any other Spring binstubs to run your tests? I'll post more once I figure out if there's a workaround.

stephen.hanson
  • 9,014
  • 2
  • 47
  • 53
0

As indicated in other response, it has to do with parallelized workers. this is logical: methods and objects can be linked so only a single worker can step through everything and give proper statistical data

I will on occasion run with a single worker to get total data. Then when iterating through edits and tests, take advantage of all processors.

Just activate and de-activate what works for you in the moment. [Rails 7]

  # Run tests in parallel with specified workers
#  parallelize(workers: :number_of_processors)
#  run with this for good coverage data
  parallelize(workers: 1)
Jerome
  • 5,583
  • 3
  • 33
  • 76