2016-12-29 2 views
0

Я пытаюсь написать неудачный тест Rspec. Фактический тест связан с гораздо более длинным кодом, но я сузил проблему до метода класса, который он тестирует.Rspec передает метод класса, но метод экземпляра с ошибкой

Вот тест в Rspec:

context "For '.CASH.' as a stock" do 
    let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') } 

    describe "When update_stock runs on it" do 
    it "should still have an 'Available' status" do 
     # status should be 'Error' and test should fail 
     Stock.change_to_error 
     expect(cash.status).to eq('Available') 
    end 
    end 
end 

Это тестирует метод класса модели в Stock.rb:

def self.change_to_error 
    self.all.each do |stock| 
    stock.status = "Error" 
    stock.save 
    end 
end 

По какой-то причине, это проходит. Однако, если я изменил его использовать метод экземпляра, он потерпит неудачу, как это необходимо:

Если stock_spec.rb изменен метод экземпляра:

context "For '.CASH.' as a stock" do 
let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') } 

    describe "When update_stock runs on it" do 
    it "should still have an 'Available' status" do 
     # status should be 'Error' and test should fail 
     cash.change_to_error 
     expect(cash.status).to eq('Available') 
    end 
    end 
end 

И если метод класса stock.rb превратился в экземпляр метод:

def change_to_error 
    self.status = 'Error' 
    self.save 
end 

Это пройдет. К сожалению, я должен использовать метод класса вместо метода экземпляра, потому что я хочу обновить все запасы в БД. Методы «Change_to_error» находятся здесь, чтобы выяснить проблему. Кто-нибудь знает, почему он проходит как метод класса, когда он должен потерпеть неудачу? Но это неправильно, когда используется метод экземпляра?

Фактически, происходит то, что метод класса не изменяет атрибут статуса «cash», но метод экземпляра делает это. Я не знаю, почему это происходит.

FYI, я использую RSpec рельсы

+1

Можете ли вы попробовать изменить 'stock.save' на' stock.save! '? Если что-то не так, это вызовет исключение. – 31piy

+0

Я пробовал это. Не помогло. Другие идеи? – HoodieOnRails

+0

Попробуйте использовать 'Stock.find_each {| stock | stock.update_column (: status, 'Error')} '. – 31piy

ответ

1

Решение: Нужно поставить «cash.reload» после «» Stock.change_to_error и перед ожидать линии.

При использовании let! объект создается перед тестом. Обновление базовых данных за пределами объекта приводит к устареванию экземпляра. Вызов reload на нем заставляет ActiveRecord обновлять его из базы данных.


При использовании let, RSpec не не вызывает блок до тех пор, в первый раз вы ссылаться на атрибут, в данном случае, cash. Итак, в вашем первом примере вы используете change_to_error без каких-либо записей, а затем проверяете статус на cash, запись, которая создается на линии с помощью expect. В вашем втором примере создается объект cash, а затем изменен на ошибку. Я бы рекомендовал закрыть ваш журнал, чтобы подтвердить это (tail -f log/test.log)

Если вы измените на let!, RSpec создаст объект до запуска каждого примера. Другой альтернативой является ссылка cash в вашем примере, прежде чем звонить change_to_error на все созданные записи.

+0

К сожалению, это не сработало. Даже если я использую цикл before и использую переменную экземпляра @cash вместо let (: cash), она не работает. Любые другие идеи? – HoodieOnRails

+0

Хотя это не решило проблему, я понимаю, что ваше наблюдение верное в коде, который я изложил выше. – HoodieOnRails

+1

Попробуйте перезагрузить 'cash' перед проверкой статуса. Теперь, когда вы используете let !, модель создается, ваш метод класса изменяет основные модели, но ваш экземпляр 'cash' может по-прежнему иметь кешированное значение. Попробуйте «cash.reload!», Затем проверьте статус. – mroach

Смежные вопросы