In app/models/car.rb
the class method stock
looks in part like this:
def self.stock
raise Exception, "Property amount not set" if Property.get(:amount).nil?
...
end
This Property is accessable by the user through all CRUD operations. I now want to test that if that Property is truly deleted an standard expection should be thrown. Therefore i created in my rspec model the following example group
describe '.stock' do
describe 'if property is not set' do
before(:all) {Property.where(name: 'amount').map(&:destroy)}
it 'raises an exception' do
expect{Car.stock}.to raise_error (Exception)
end
after (:all) {Property.create! name: 'amount', value: 10}
end
describe 'if property is set' do
before (:all) do
create :car_listed
create :car_sold
end
it 'calculates the correct amount of sellable cars' do
amount = 10 - Car.where(state: "sold")
expect(Car.stock).to eq(amount)
end
end
end
I make sure all Properties with that name get deleted. In the it-block i then expect the exception to be trown. After the it-block i created the property again because other tests depend on it.
In the app are properties which are not going to change during tests. So database_cleaner
does not truncate the properties table. It got set through a seeds file.
config.before(:suite) do
DatabaseCleaner.strategy = :truncation, {except: %w[properties]}
end
The test however fails with
Car
.stock
if property is set
calculates the correct amount of sellable cars
if property is not set
raises an exception (FAILED - 1)
Failures:
1) Car.stock if property is not set not set raises an exception
Failure/Error: expect{Car.stock}.to raise_error (Exception)
expected Exception but nothing was raised
# ./spec/models/car_spec.rb: `block (4 levels) in <top (required)>'
My question is now how do i have to delete this property properly ((:), so that my exception gets raised.
There are easier ways to test this that do not touch the database. Here's how to approach the problem using stubs:
describe '.stock' do
before do
allow(Property).to receive(:get).with(:amount).and_return(amount)
end
context 'when property amount is NOT set' do
let(:amount) { nil }
it 'raises an exception' do
expect { Car.stock }.to raise_error(Exception)
end
end
context 'when amount property is set' do
let(:amount) { 10 }
before do
create :car_listed
create :car_sold
end
it 'does NOT raise an exception' do
expect { Car.stock }.to_not raise_error(Exception)
end
it 'calculates the correct amount of sellable cars' do
expect(Car.stock).to eq(amount - 1)
end
end
NOTE: I'm unsure about that last test since you didn't include that code.