Godzilla74 Godzilla74 - 6 months ago 17
Ruby Question

RSpec validation fails with little explaination

I've created an RSpec test to simply test if my model is valid with the given info, it should be, yet my test is still failing. I'm hoping someone can see why since I've stared at this all day yesterday.

I'm also using MongoDB (not sure if that matters).

models/stock.rb

class Stock
include Mongoid::Document
field :symbol, type: String
field :last_trade_price, type: Integer
field :ask, type: Integer
field :change, type: Integer
field :change_percent, type: String
field :market_cap, type: String
field :avg_volume, type: Integer
field :change_from_year_high, type: Integer
field :change_from_year_low, type: Integer
field :change_from_year_high_percent, type: Integer
field :change_from_year_low_percent, type: Integer
field :year_high, type: Integer
field :year_low, type: Integer
field :day_high, type: Integer
field :day_low, type: Integer
field :day_range, type: String
field :ebitda, type: String
field :eps_estimate_current_year, type: Integer
field :eps_estimate_next_year, type: Integer
field :eps_estimate_next_quarter, type: Integer


validates :symbol, :last_trade_price, :ask, :change, :change_percent, :market_cap,
:avg_volume, :change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
:change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low, :day_range,
:ebitda, :eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter, presence: true

validates :last_trade_price, :ask, :change, :avg_volume,
:change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
:change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low,
:eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter, numericality: true

validates_uniqueness_of :symbol

end


spec/factories.rb

FactoryGirl.define do
factory :stock do
symbol "AAPL"
last_trade_price 92.51
ask 92.78
change -0.91
change_percent "-0.91 - -0.97"
market_cap "512.93B"
avg_volume 37776500
change_from_year_high -40.46
change_from_year_low 0.66
change_from_year_high_percent -30.43
change_from_year_low_percent 0.72
year_high 132.97
year_low 91.85
day_high 93.57
day_low 92.46
day_range "92.46 - 93.57"
ebitda "82.79B"
eps_estimate_current_year 8.29
eps_estimate_next_year 9.15
eps_estimate_next_quarter 1.67
end
end


spec/models/stock_spec.rb

describe Stock do
let(:stock) { build(:stock) }

it "should be valid if all information is provided" do
expect(stock).to be_valid
end
end


My output from running the rspec test is:

Failures:

1) Stock should be valid if all information is provided
Failure/Error: expect(stock).to be_valid
expected `#<Stock _id: 5734dd60b8066872f6000000, symbol: "AAPL", last_trade_price: 92, ask: 92, change: 0, change_percent: "-0.91 - -0.97", market_cap: "512.93B", avg_volume: 37776500, change_from_year_high: -40, change_from_year_low: 0, change_from_year_high_percent: -30, change_from_year_low_percent: 0, year_high: 132, year_low: 91, day_high: 93, day_low: 92, day_range: "92.46 - 93.57", ebitda: "82.79B", eps_estimate_current_year: 8, eps_estimate_next_year: 9, eps_estimate_next_quarter: 1>.valid?` to return true, got false
# ./spec/models/stock_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.02311 seconds (files took 1.72 seconds to load)
1 examples, 1 failure

Failed examples:

rspec ./spec/models/stock_spec.rb:4 # Stock should be valid if all information is provided

Randomized with seed 36574


From looking at the error, it seems that all of the information was built into the factory test object, so I'm unsure why the test is getting
false
instead of the
true
it's expecting.

Thanks for any help!

max max
Answer

You can test what fields are giving an error by modifiying the spec:

describe Stock do
  let(:stock) { build(:stock) }

  it "should be valid if all information is provided" do
    #expect(stock).to be_valid
    stock.valid?
    expect(stock.errors.full_messages).to eq []
  end
end

However even as such the spec has very little actual value - you're just testing that your factory has all the required fields. If it didn't you would get failures in other specs anyways.

Also if you are grouping a bunch of similar validations by type you might want to use the longhand methods instead as it is much easier to read:

  validates_presence_of :symbol, :last_trade_price, :ask, :change, :change_percent, :market_cap,
            :avg_volume, :change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
            :change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low, :day_range,
            :ebitda, :eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter

Added

When defining factories you should use sequences or computed properties to ensure that unique fields are unique - otherwise your validations will fail if you create more than one record from your factory!

FactoryGirl.define do
  factory :stock do
    sequence :symbol do |n|
      "TEST-#{n}"
    end
    last_trade_price 92.51
    ask 92.78
    change -0.91
    change_percent "-0.91 - -0.97"
    market_cap "512.93B"
    avg_volume 37776500
    change_from_year_high -40.46
    change_from_year_low 0.66
    change_from_year_high_percent -30.43
    change_from_year_low_percent 0.72
    year_high 132.97
    year_low 91.85
    day_high 93.57
    day_low 92.46
    day_range "92.46 - 93.57"
    ebitda "82.79B"
    eps_estimate_current_year 8.29
    eps_estimate_next_year 9.15
    eps_estimate_next_quarter 1.67
  end
end

Gems like FFaker are really helpful here. See the FactoryGirl docs for more info.

Also you should use a gem like database_cleaner (Yes it works for mongoid) to clean out your database between specs - the reason your validation is currently failing is that you have residual test state from some other test which is effecting the result.