【问题标题】:Write test cases for model using rspec with 100% coverage使用 rspec 为模型编写测试用例,覆盖率为 100%
【发布时间】:2018-04-13 17:50:55
【问题描述】:

您好,我正在使用 ruby​​-2.5.0 和 Rails 5 开发 RoR 项目。我有一个 forgot_password 模型,我正在使用 rspec 为其编写测试用例。 我在模型中有两种方法如下:-

class ForgotPassword < ApplicationRecord
  before_create :create_token

  def self.create_record(user)
    forgot_password = create!(expiry: Time.zone.now + ENV['VALIDITY_PERIOD'].to_i.hours)
    send_forgot_password_email user, forgot_password
    forgot_password
  end

  def self.send_forgot_password_email(user, forgot_password)
    return if Rails.env == 'test'
    Mailjet::Send.create(from_email:  ENV['MIALJET_DEFAULT_FROM'],
                         from_name: ENV['MIALJET_FROM_NAME'],
                         to: user.email,
                         subject: 'Forgot Password',
                         text_part: forgot_password.token)
  end

  private

  def create_token
    self.token = SecureRandom.urlsafe_base64(nil, false)
  end
end

第一种方法创建 forgot_password 记录,另一种方法使用 mailjet 发送电子邮件。 我的规格如下:-

spec/models/forgot_password_spec.rb
require 'rails_helper'

RSpec.describe ForgotPassword, type: :model do
  user = FactoryBot.create(:user)

  describe '#create_record' do
    it 'do not raise_error' do
      expect { ForgotPassword.create_record(user) }.not_to raise_error
    end

    it 'increment the count of ForgotPassword' do
      expect { ForgotPassword.create_record(user) }.to change(ForgotPassword, :count)
        .from(0).to(1)
    end

    it 'return instance of ForgotPassword' do
      expect(ForgotPassword.create_record(user)).to be_instance_of(ForgotPassword)
    end

    it 'return nil when env is test' do
      expect(ForgotPassword.send_forgot_password_email(user,ForgotPassword.last)).to eq(nil)
    end
  end
end

当我运行RAILS_ENV=test bundle exec rake 时,我得到了Coverage (99.58%) is below the expected minimum coverage (100.00%) 请帮我写下丢失的案例。当我从 send_forgot_password_email 方法中删除 return if Rails.env == 'test' 这一行时,它覆盖了 100%。请帮我修复它。提前致谢。

【问题讨论】:

  • 我会谨慎使用return if Rails.env == 'test' 这样的行。我可能会在这里完全删除它,因为您希望您的测试尽可能接近真实的东西。 Rails 在测试模式下有一个特性,它实际上并不发送电子邮件。相反,它会为您将它们收集到一个数组中,以便您可以测试电子邮件的内容。如果你删除那条线,你应该很高兴。
  • 您的应用程序代码不应该了解 Rails 环境。即没有像Rails.env 这样的测试东西。您应该拥有的是,取决于您的环境,注入/重写/模拟。例如,如果您想测试地理定位服务(如 Google),您的测试套件实际上不应通过 API 执行调用,而应模拟仅针对测试环境的响应。
  • 顺便说一下,您可以在此处阅读邮件测试:guides.rubyonrails.org/testing.html#testing-your-mailers。该文档讨论了ActionMailer::Base.deliveries,您可以使用它来查看您的邮寄者是否在做他们的工作。
  • 另一个建议,以 100% 的覆盖率为目标并不是 IMO 的最佳主意。达到这一点需要很多时间。网上有很多关于这个的讨论。瞄准 85-90% 似乎是常态。
  • 同意,不要将环境相关的东西放在你的代码中。这很可能属于您的规范助手。绝对模拟您的外部呼叫,或使用 VCR(喜欢它!)之类的东西来做出真正的响应,并将其用作您的模拟。祝你好运!

标签: ruby-on-rails rspec-rails rubocop-rspec


【解决方案1】:

使用MailJet through ActionMailer。确保 ActionMailer 不会在测试环境中发送电子邮件:

# config/environments/test.rb
config.action_mailer.delivery_method = :test

并使用enqueue_email RSpec matcher。

另外,不要这样做:

user = FactoryBot.create(:user)

示例范围之外。有关说明,请参阅this work-in-progress rubocop-rspec cop。 如果您的意图是在多个示例中重用记录,请查看 let_it_be from test-prof。

【讨论】:

    猜你喜欢
    • 2012-03-23
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2019-11-06
    相关资源
    最近更新 更多