pandancode
pandancode

Reputation: 95

Why is Rspec and SimpleCov Model Coverage nearly 100% by default

I found that SimpleCov always flags all standard (i.e. nothing fancy like custom method validations) validations in the model(s) to be "fully hit / tested". This confuses me as I would've thought that one should be writing tests to hit every (single) validation (if one was so minded) in the models - but no, with no (sensible) tests written, simplecov shows all model validations as tested.

I'm new to rails and testing so apologies if it's something very fundamental and obvious. I've spent like a day running around this issue, found a few interesting issues that have been resolved but still struggle to understand it.

Setup: default Rails 7.0.3, Ruby 3.0.3, program using rspec for testing & simplecov for coverage tracking. I've replicated this using a simple rails new project with the default devise user model where I've added title, first_nama, and last_name fields to the user model, and required the title field via a simple validation in the model.

# 20221102142351_add_name_to_users.rb
class AddNameToUsers < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :title, :string
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string
  end
end

# user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  validates :title, presence: true
end

Problem encountered: without writing a single line in the user_spec.rb file (i.e. with no tests), simplecov tells me that validates :title, presence: true has been hit. I know this is kinda of trivial here, but it's less trivial if one has several models and a lot of (standard) validations.

If you want to replicate this:

  1. Add rspec gem in testing & development and generate the user model spec file as per documentation
  2. Add the simplecov gem in testing as per documentation starting simplecov in the spec_helper.rb file - and don't forget the next point
  3. Hash out the capybara gem in testing (it causes an error as per below when running rspec spec)
An error occurred while loading ./spec/models/user_spec.rb. - Did you mean?
                    rspec ./spec/spec_helper.rb

Failure/Error: require_relative '../config/environment'

LoadError:
  cannot load such file -- addressable/uri

You can play around with the user model spec file, but irrespective of what you do, the validates :title, presence: true always lights as as "hit".

How does one / simplecov "know" when the (model) validations have "truly" been tested?

# user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  # pending "add some examples to (or delete) #{__FILE__}"

  describe "User validations" do
    it "should be valid for a user with all fields filled out" do
      @valid_user = User.new(email: "[email protected]", password: "testtest", title: "Mr", first_name: "Jack", last_name: "Sparrow")
      @valid_user.save
      expect(@valid_user.valid?).to be true
    end

    it "should be invalid for a user without a title" do
      @invalid_user = User.new(email: "[email protected]", password: "testtest", first_name: "Jack", last_name: "Sparrow")
      @invalid_user.save
      expect(@invalid_user.valid?).to be false
    end
  end
end

Upvotes: 1

Views: 708

Answers (1)

Cluster
Cluster

Reputation: 5617

This is because the lines are part of the class body and not a function that is being called. All you have to do to get "coverage" is to have the class itself invoked by the Zeitwerk loader, by referencing the class name via RSpec.describe User.

This would also be true in controllers for things like before_action lines or other helper methods that live at the class level. We notice them less because our models tend to be much more heaviliy decorated with class level method calls.

Upvotes: 1

Related Questions