Adriano Godoy
Adriano Godoy

Reputation: 1568

Short way for tests validations in Rspec

I want a simple way to test my validations. My test focus are integrations, not validations, and I don't working with TDD. That being said, I want to replace:

# Estate model specs

describe "#name" do
  it "is required" do
    estate.name = nil
    estate.valid?
    expect(estate.errors).to have_key(:name)
  end
end

describe "#company" do
  it "is required" do
    estate.company = nil
    estate.valid?
    expect(estate.errors).to have_key(:company)
  end
end

# and so on..

to some like:

# Estate model specs

requiredFields = [:name, :company, :price, :region, :regions, :typologies, :image]
requiredFields.each do |requiredField|
  describe "##{requiredField}" do
    it "is required" do
      estate[requiredField] = nil
      estate.valid?
      expect(estate.errors).to have_key(requiredField)
    end
  end
end

The fields name and price works, the problem is in associations:

Estate
  is an instance of Estate
  validations
    with required fields
      should be valid
    #name
      is required
    #company
      is required (FAILED - 1)
    #price
      is required
    #region
      is required (FAILED - 2)
    ...

I think that problem is estate[requiredField]. If I change to company_id will work. How can I do something like estate.requiredField in foreach?

Upvotes: 0

Views: 80

Answers (2)

dimuch
dimuch

Reputation: 12818

Try to use object.send

estate.send("#{requiredField}=", value) # setter, estate.requiredField=value
estate.send(requiredField) # getter, estate.requiredField

Or use https://github.com/thoughtbot/shoulda-matchers for such kind of tests

Upvotes: 1

Kristján
Kristján

Reputation: 18803

You can perform estate.requiredField using Ruby's send method, which invokes its argument as a method on the receiver:

estate.send(requiredField)

Since you're assigning, you'll need to interpolate an = into the field name. The foo= method takes an argument, which you pass as continued arguments to send after the method name:

estate.send("#{requiredField}=", nil)`

Something to be aware of is that since send ends up calling the requested method from within the receiver, you might end up bypassing protected or private methods.

class Dog
   private
   def bark
     puts 'Woof'
   end
 end

Dog.new.bark
# NoMethodError: private method 'bark' called for #<Dog:0x007fd28bad7590>

Dog.new.send :bark
# Woof

Upvotes: 2

Related Questions