2012-10-23 34 views
6

Tôi có hai lớp:Kiểm tra nhanh (Rspec) có và không có Rails

1.Sale là phân lớp của ActiveRecord; công việc của nó là duy trì dữ liệu bán hàng cho cơ sở dữ liệu.

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 là lớp Ruby chuẩn; công việc của nó là tạo và biểu thị thông tin về Bán hàng.

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 

Bởi vì tôi muốn sử dụng TDD và tôi muốn thử nghiệm của tôi để chạy rất nhanh, tôi đã viết một spec cho SalesReport mà không không tải 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 

này kiểm tra hoạt động khi tôi chạy bundle exec rspec spec/models/report_spec.rb.

Tuy nhiên, kiểm tra này không thành công khi tôi chạy bundle exec rake spec với lỗi superclass mismatch for class Sale (TypeError). Tôi biết lỗi xảy ra vì Tap được xác định bởi sale.rb và nội dòng trong thông số kỹ thuật.

Vì vậy, câu hỏi của tôi là có cách để Stub (hoặc Mock hoặc Double) một lớp nếu lớp đó không được xác định? Điều này sẽ cho phép tôi xóa nội tuyến class Sale; end, cảm giác như bị hack.

Nếu không, làm cách nào để thiết lập các thử nghiệm của mình sao cho chúng chạy chính xác cho dù tôi chạy bundle exec rspec hoặc bundle exec rake spec?

Nếu không, cách tiếp cận của tôi để viết kiểm tra nhanh có sai không ?!

Cuối cùng, tôi không muốn sử dụng Spork. Cảm ơn!

Trả lời

4

RSpec của thời gian gần đây thêm stub_const là được thiết kế đặc biệt cho các trường hợp như sau:

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 

Bạn cũng có thể muốn sử dụng rspec-fire để sử dụng thử nghiệm tăng gấp đôi thay cho Sale tự động kiểm tra tất cả các phương pháp giả mạo/phân tích tồn tại trên lớp Sale thực khi chạy thử nghiệm của bạn với lớp thực tế được tải Sale (ví dụ: khi bạn chạy bộ kiểm tra của bạn):

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 

Nếu bạn đổi tên total_for_duration trên lớp thực Sale, rspec bắn đạn thật sẽ cung cấp cho bạn một lỗi khi bạn thử phương pháp này vì nó không tồn tại trên lớp thực sự.

+0

Cảm ơn Myron Marston! – Mike

4

Một cách đơn giản sẽ là để kiểm tra xem "bán" đã được xác định

unless defined?(Sale) 
    class Sale; end 
end 

bán không cần phải là một lớp học hoặc trong thử nghiệm của bạn như vậy:

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

Cảm ơn. Trông đầy hứa hẹn. – Mike

Các vấn đề liên quan