簡體   English   中英

使用和不使用Rails的快速(Rspec)測試

[英]Fast (Rspec) tests with and without Rails

我有兩節課:

1.Sale是ActiveRecord的子類; 它的工作是將銷售數據保存到數據庫中。

class Sale < ActiveRecord::Base
  def self.total_for_duration(start_date, end_date)
    self.count(conditions: {date: start_date..end_date})
  end
  #...
end

2.SalesReport是一個標准的Ruby類; 它的工作是生成和繪制有關銷售的信息。

class SalesReport
  def initialize(start_date, end_date)
    @start_date = start_date
    @end_date = end_date
  end

  def sales_in_duration
    Sale.total_for_duration(@start_date, @end_date)
  end
  #...
end

因為我想使用TDD並且我希望我的測試運行得非常快 ,所以我為SalesReport編寫了一個不加載Rails的規范:

require_relative "../../app/models/sales_report.rb"

class Sale; end
# NOTE I have had to re-define Sale because I don't want to
# require `sale.rb` because it would then require ActiveRecord.

describe SalesReport do
  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

當我運行bundle exec rspec spec/models/report_spec.rb時,此測試有效

但是,當我運行bundle exec rake spec並且superclass mismatch for class Sale (TypeError)的錯誤superclass mismatch for class Sale (TypeError)時,此測試失敗。 我知道錯誤正在發生,因為Tap是由sale.rb定義並在規范中內聯。

所以我的問題是,如果沒有定義該類,有一種方法可以將Stub(或Mock或Double)作為一個類嗎? 這將允許我刪除內聯class Sale; end class Sale; end ,這感覺就像一個黑客。

如果沒有,如何運行bundle exec rspecbundle exec rake spec ,我如何設置我的測試以使它們正確運行?

如果沒有,我寫快速測試的方法是錯誤的嗎?!

最后,我不想使用Spork。 謝謝!

一種簡單的方法是檢查是否已定義“銷售”

unless defined?(Sale)
  class Sale; end
end

在您的測試中,銷售不一定是一個類,所以:

unless defined?(Sale)
  Sale = double('Sale')
end

RSpec最近添加的stub_const專門針對以下情況設計:

describe SalesReport do
  before { stub_const("Sale", Class.new) }

  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

您可能還想使用rspec-fire來代替Sale來使用測試雙Sale來自動檢查真實Sale類中存在的所有模擬/存根方法在運行帶有真實Sale類的測試時(例如,當您運行測試時)套房):

require 'rspec/fire'

describe SalesReport do
  include RSpec::Fire

  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      fire_replaced_class_double("Sale")
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

如果在真正的Sale類上重命名total_for_duration ,則在模擬方法時rspec-fire會給出錯誤,因為它在實際類中不存在。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM