Rspec instance_double creates intermittent spec errors

I get intermittent test failures when using instance_double.

I have a file with 4 specifications. Here is the source:

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 

This is a Rails 4.1.4 application. Internally, SubmitPost sets submit_at and causes it to be saved on sent mail. My Post model is as follows:

 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 

This is super vanilla.

When I run rake , rspec or bin/rspec , I get all four tests with an error of 20% - 30% of the time. The error message is always:

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

If I tag one of the specs with focus: true , then one spec will fail 100% of the time.

If I replaced instance_double with double , all specifications will succeed for 100% of the time.

It seems that instance_double is having a hard time outputting the methods available in the Post class. It also seems somewhat random and time-based.

Has anyone encountered this problem? Any ideas what might be wrong? Any feeling how to solve the problem? Naturally, inserting a debug breakpoint causes specifications to skip 100% of the time.

+6
source share
1 answer

The problem you see is that ActiveRecord dynamically creates column methods. instance_double uses 'Post' to search for methods to make sure you complete them correctly (if the class does not already exist or has not been loaded).

When the previous specification loads the model, ActiveRecord will create these dynamic methods so that your specification passes when RSpec can find the methods (with respond_to? ). In battery life, the model was not previously used, so ActiveRecord has not yet created dynamic methods, and your test failed as you are.

The workaround for this is to force ActiveRecord to load dynamic methods when called in your specification:

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

See the RSpec documentation for further explanations and workarounds:

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

+4
source

Source: https://habr.com/ru/post/975049/


All Articles