Как тестировать цепочечные методы в Ruby on Rails, используя Rspec - PullRequest
3 голосов
/ 01 июля 2011

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

Скажем, у меня есть следующие модели ...

class User
  has_many :interviews

  def interview_grade
    interviews.average(:score).round unless interviews.empty?
  end
end

class Interview
  belongs_to :user
end

И в user_spec.rb У меня есть ...

describe "interview_grade" do
  let(:user) {User.new}
  context "when the user has interviews" do
    before { user.stub_chain(:interviews, :empty?){false} }
    it "should return an average of the appraisal ratings" do
      user.interviews.should_receive(:average).with(:score).and_return(3.2)
      user.work_history_grade.should == 3
    end
  end

  context "when the user has no interviews" do
    before {Interview.destroy_all}
    it "should return nil" do
      user.interview_grade.should be_nil
    end
  end

end

Эти испытания пройдены, но мне они кажутся хрупкими.Что если interview_grade действительно вычислит сумму баллов (например).Поскольку я просто проверяю, что вызывается определенная цепочка методов, этот проходной тест не скажет мне, что результат на самом деле неверный.

Я попытался ввести заглушку user.interviews, чтобы настроить доступные оценки.чтобы тест работал, но в Rails 3 это сложно сделать из-за того, что ассоциации загружаются лениво.то есть я не могу просто создать массив объектов Interview, потому что он не реагирует на среднее значение method.

Любой совет с благодарностью.

Ответы [ 2 ]

1 голос
/ 12 июня 2015

Возвращаясь к этому 3 года спустя. Я бы подошел к этому совершенно по-другому.

Преимущество приведенного ниже кода состоит в том, что для написания тестов для InterviewGrader мне больше не нужно беспокоиться о том, как набраны баллы.

Я просто выставляю оценки и проверяю, дает ли я правильные результаты.

Также мне никогда не придется беспокоиться о базовой реализации InterviewGrader. Однако, если логика была изменена позднее, тесты не пройдут.

Новый метод scores для User необходимо проверить отдельно.

class InterviewGrader

  def self.run scores
    new(scores).run
  end

  attr_reader :scores

  def initialize(scores)
    @scores = scores
  end

  def run
    scores.inject { |sum, score|
      sum + score
    }.to_f / number_of_scores
  end

  private

  def number_of_scores
    scores.length
  end

end


class User
  has_many :interviews

  def scores
    interviews.map(&:score)
  end

  def interview_grade
    InterviewGrader.run(scores)
  end
end

class Interview
  belongs_to :user
end
0 голосов
/ 18 июля 2011

Это неправильное использование заглушки и насмешек.

В этом случае вам следует только проверить, что interview_grade работает, когда average возвращает ноль (и это только в случае использования interviews.empty?).

Метод average проверяется самими рельсами. round метод по рубиновым тестам (наверное). Таким образом, вам не нужно проверять эти методы. Это общая идея для тестирования только вашего собственного кода.

И если вы хотите проверить, как рассчитывается survey_grade, вы должны создать тестовые данные (с приборами или фабриками). Потому что вы должны тестировать отдельную (в некоторых случаях) часть системы, и в этом случае разделение является неправильным: journals.average и интервьюs.empty? зависят от вашего кода, но в спецификации они независимы.

def interview_grade
  interviews.average(:score).try(:round)
end

Если вы переписываете свой метод таким образом, вам не нужно заглушки и насмешки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...