2012-10-23 2 views
6

두 클래스가 있습니다.Rails가있는 경우와없는 경우의 빠른 (Rspec) 테스트

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에 대한 사양 작성한 실행하려는 때문에 :

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 실행할 때 작동합니다.

그러나 오류 superclass mismatch for class Sale (TypeError)을 사용하여 bundle exec rake spec을 실행하면이 테스트가 실패합니다. Tap이 sale.rb으로 정의되고 사양 내에서 인라인으로 오류가 발생했음을 압니다.

내 질문에 클래스가 정의되지 않은 경우 클래스를 스텁 (또는 모의 또는 이중)하는 방법이 있습니까? 이렇게하면 해킹 같은 느낌의 인라인 class Sale; end을 제거 할 수 있습니다.

그렇지 않은 경우 bundle exec rspec 또는 bundle exec rake spec을 실행해도 테스트가 올바르게 실행되도록 설정하려면 어떻게해야합니까?

그렇지 않은 경우 빠른 테스트 작성에 대한 나의 접근 방식이 잘못 되었습니까?!

마지막으로 Spork를 사용하고 싶지 않습니다. 감사! 의 최근 stub_const 추가

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

답변

4

RSpec에는 "판매"가 이미

unless defined?(Sale) 
    class Sale; end 
end 

매각이 너무 테스트의 클래스 중 하나 일 필요는 없다 정의되어있는 경우

+0

감사합니다 Myron Marston! – Mike

4

간단한 방법은 확인하는 것입니다 다음과 같은 경우에 맞게 특별히 설계되었습니다.

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 

012 실제 Sale 클래스가로드 된 상태에서 테스트를 실행하면 실제 Sale 클래스에 모의/스텁 된 모든 메소드가 자동으로 검사되는 Sale 대신테스트 이중을 사용하는 것이 좋습니다. 당신이 당신의 테스트 스위트를) 실행하면 사용자가 실제 Sale 클래스에 total_for_duration 이름을 변경하면

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 

는 RSpec에 불는 실제 클래스에 존재하지 않기 때문에 당신이 방법을 조롱 할 때 당신에게 오류를 줄 것이다.

+0

감사합니다. 유망 해 보인다. – Mike