RSpec: тестирование моделей с помощью методов, которые вызывают update_attributes - PullRequest
4 голосов
/ 21 января 2012

Новичок RSpec здесь.

Я пытаюсь протестировать свои модели, в которых есть методы, использующие update_attributes для обновления значений других моделей.

Я уверен, что значения сохраняются в базе данных, ноони не передают спецификации.

Однако, когда я включаю что-то вроде @user.reload, это работает.

Мне интересно, делаю ли я что-то неправильно.В частности, как следует тестировать модели, которые изменяют атрибуты других моделей?

ОБНОВЛЕНО кодом:

describe Practice do

before(:each) do
    @user = build(:user)
    @user.stub!(:after_create)
    @user.save!

    company = create(:acme)
    course = build(:acme_company, :company => company)
    course.save!

  @practice = create(:practice, :user_id => @user.id, :topic => "Factors and Multiples" )
end

describe "#marking_completed" do

    it "should calculate the points once the hard practice is done" do
        @practice.question_id = Question.find(:first, conditions: { diff: "2" }).id.to_s
        @practice.responses << Response.create!(:question_id => @practice.question_id, :marked_results => [true,true,true,true])
        @practice.save!

        lambda {
            @practice.marking_completed
            @practice.reload # <-- Must add this, otherwise the code doesn't work
        }.should change { @practice.user.points }.by(20)
    end
end

end

На практике. Rb

def marking_completed       

# Update user points
user.add_points(100)
self.completed = true
self.save!

end

In User.rb

def add_points(points)
self.points += points
update_attributes(:points => self.points)

end

1 Ответ

5 голосов
/ 22 января 2012

Что происходит, так это то, что пользовательский объект кэшируется в переменной @practice, что требует перезагрузки после обновления пользователя. С текущей спецификацией вы мало что можете сделать по этому поводу, но вы можете подумать о том, что вы на самом деле тестируете. Мне кажется странным, что ваша спецификация относится к модели практики, но утверждение should change { @practice.user.points }.by(20) действительно описывает поведение пользователя.

Я бы лично немного больше отделил модели "Практика" и "Пользователь" в вашей спецификации и самостоятельно проверил бы их поведение.

describe "#marking_completed" do
  before do
    @practice.question_id = Question.find(:first, conditions: { diff: "2" }).id.to_s
    @practice.responses.create!(:question_id => @practice.question_id, :marked_results => [true,true,true,true])
    @practice.save!
  end

  it "should calculate the points once the hard practice is done" do
    @practice.user.should_receive(:add_points).with(20).once
    @practice.marking_completed
  end
end

Тогда я бы добавил отдельный тест для модели User:

describe User do
  it 'should add specified points to a user' do
    lambda { subject.add_points(100) }.should change { subject.points }.by(100)
  end
end

Еще одно замечание заключается в том, что неясно, что возвращает Question.find, или почему баллы пользователя изменяются на 20 в вашем тесте.

...