Hari Shankar
Hari Shankar

Reputation: 84

Stubbing validation on an ActiveRecord across the RSpec test suite

I have an ActiveRecord object which gets created/saved in approximately 50% of my RSpec suite. I want to stub a validation of it across the suite apart from the context where I am explicitly testing the behaviour of validation.

To achieve this, I stubbed it globally using config

config.before(:each) do
  allow_any_instance_of(Activerecord::Abc).to receive(:abc_validate).and_return(true)
end

and then overwrote the stub in the specific context

context "Validations" do
  context "abc_validate" do
    before :each do
      allow_any_instance_of(Activerecord::Abc).to receive(:abc_validate).and_call_original
    end

    it "should ..... " do
      ........
    end
  end
end

This meets my requirement. However, it is not efficient, as, although I need the stub only for approximately 50% of my RSpec test suite, I am actually stubbing it for every unit test. Even the unit tests which don't need the stub will have a stubbed function.

Is there a better way to do it?

I thought of one another approach: Instead of stubbing the method, I can re-open the class in RSpec and over-write the custom-validation function itself.

Activerecord::Abc.class_eval do
  def abc_validate(testing_self = false)
    testing_self ? super : true
  end
end

However, this approach feels too hacky.

Version details -

  1. Rails 4.2.4
  2. Rspec 3.3.0

Upvotes: 0

Views: 2665

Answers (1)

Dani
Dani

Reputation: 1022

Personally I don't like the idea of using an invalid mock object across your entire suite. I think it's prone to bugs since tests will treat the object as a valid one and might use the functionality of the object which exposes it's invalidity, resulting in false negatives.

So I would suggest turning things around by using a valid object throughout your tests expect for the specific context in which you're testing it's creation and validations.

If creating a valid object requires a lot of set up you can use fixtures or the FactoryGirl gem to centrelize this logic in a single place. Creating a valid object will then be a simple issue of calling FactoryGirl.create(:abc).

Upvotes: 1

Related Questions