2014-09-10 18 views
6

Tôi đang gặp lỗi thất bại khi sử dụng instance_double.Rspec's instance_double tạo các lỗi thất bại liên tục

Tôi có tệp có 4 thông số kỹ thuật trong đó. Đây là nguồn:

require 'rails_helper' 

describe SubmitPost do 
    before(:each) do 
    @post = instance_double('Post') 
    allow(@post).to receive(:submitted_at=) 
    end 

    context 'on success' do 
    before(:each) do 
     allow(@post).to receive(:save).and_return(true) 

     @result = SubmitPost.call(post: @post) 
    end 

    it 'should set the submitted_at date' do 
     expect(@post).to have_received(:submitted_at=) 
    end 

    it 'should call save' do 
     expect(@post).to have_received(:save) 
    end 

    it 'should return success' do 
     expect(@result.success?).to eq(true) 
     expect(@result.failure?).to eq(false) 
    end 
    end 

    context 'on failure' do 
    before(:each) do 
     allow(@post).to receive(:save).and_return(false) 

     @result = SubmitPost.call(post: @post) 
    end 

    it 'should return failure' do 
     expect(@result.success?).to eq(false) 
     expect(@result.failure?).to eq(true) 
    end 
    end 

end 

Đây là ứng dụng Rails 4.1.4. Bên trong, SubmitPost đặt submitted_at và các cuộc gọi được lưu trên Bài đăng đã được gửi qua. Mô hình Đăng của tôi trông giống như sau:

class Post < ActiveRecord::Base 

    validates :title, presence: true 
    validates :summary, presence: true 
    validates :url, presence: true 
    validates :submitted_at, presence: true 

    scope :chronological, -> { order('submitted_at desc') } 

end 

Đó là siêu vani.

Khi tôi chạy rake, rspec hoặc bin/rspec, tôi nhận được tất cả bốn thử nghiệm không bị 20% - 30% thời gian. Các thông báo lỗi luôn luôn là:

Failure/Error: allow(@post).to receive(:submitted_at=) 
    Post does not implement: submitted_at= 

Nếu tôi đặt tên một trong những thông số kỹ thuật với focus: true, rằng một spec sẽ thất bại 100% thời gian.

Nếu tôi thay thế instance_double bằng double, tất cả thông số kỹ thuật sẽ thành công 100% thời gian.

Có vẻ như instance_double đang gặp khó khăn khi phỏng đoán các phương thức có sẵn trên lớp Post. Nó cũng có vẻ hơi ngẫu nhiên và dựa trên thời gian.

Có ai gặp sự cố này không? Bất cứ ý tưởng những gì có thể là sai? Bất kỳ ý thức làm thế nào để đi về xử lý sự cố này? Đương nhiên, chèn một điểm ngắt gỡ lỗi làm cho các thông số kỹ thuật vượt qua 100% thời gian.

+0

Tôi có thêm một số dữ liệu về điều này. Gốc của vấn đề là môi trường Rails không được tải khi spec này chạy. Nếu tôi chỉ chạy tập tin này, nó luôn thất bại. Tôi có tổng cộng bốn tệp spec. Nếu tập tin này chạy đầu tiên, nó không thành công. Nếu cái gì khác chạy trước, nó thành công. Giả định của tôi là chạy trước đó đang tải môi trường Rails, do đó, kiểm tra này sẽ trôi qua. Tệp kiểm tra này nằm trong 'spec/interactors', do đó có thể góp phần vào vấn đề này. – EricM

+0

Dữ liệu khác. Tôi đã xác minh rằng ứng dụng/tương tác, trong đó SubmitPost sống, nằm trong eager_load_paths. Tôi cũng đã thử gắn thẻ thông số với loại:: feature. Thông báo lỗi không thay đổi. – EricM

Trả lời

4

Sự cố bạn đang thấy là ActiveRecord tạo các phương thức cột động. instance_double sử dụng 'Post' để tra cứu các phương pháp xác minh bạn đang đặt chúng chính xác (trừ khi lớp chưa tồn tại hoặc chưa được tải).

Khi thông số trước tải mô hình, ActiveRecord sẽ tạo các phương thức động đó để thông số của bạn đi qua khi RSpec có thể tìm phương thức (với cuộc gọi respond_to?). Khi chạy trong sự cô lập, mô hình chưa được sử dụng trước đó và vì vậy ActiveRecord sẽ không tạo các phương thức động và thử nghiệm của bạn không thành công như bạn đang gặp phải.

Cách giải quyết của việc này là để buộc ActiveRecord để tải các phương pháp năng động khi chúng được gọi là trong spec của bạn:

class Post < ActiveRecord::Base 
    def submitted_at=(value) 
    super 
    end 
end 

Xem tài liệu RSpec cho giải thích thêm và cách giải quyết cho vấn đề này:

https://www.relishapp.com/rspec/rspec-mocks/docs/verifying-doubles/dynamic-classes

+0

Cảm ơn vì đã giúp tôi giải quyết vấn đề này, tôi mở lớp trong một 'trước (: ngữ cảnh) làm lớp MyClass ryan2johnson9

+0

hãy viết lại nhận xét ở trên của tôi. Tôi đã tìm ra lý do tại sao đôi ("MyClass") là tốt hơn sau đó MyClass.new cho stubbing. Sau này sẽ cho phép bạn stub bất cứ điều gì, vì vậy nếu bạn thay đổi tên của phương pháp trong mã mà bạn đang stubbing trong spec, nó không thất bại trong spec và bạn nhận được một dương tính giả. sử dụng instance_double làm tăng một lỗi tốt. Để có được hiệu ứng tương tự với MyClass.new bạn cũng sẽ phải có một dòng trong spec trước khi stubbing một phương thức như thế này 'expect (my_double). To respond_to ('the_method_i_am_about_to_stub')' – ryan2johnson9

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